Files
TAIXIN/sdk/lib/video/miniMP4/mp4_encode_msi2.c

1341 lines
40 KiB
C
Raw Permalink Normal View History

#include "basic_include.h"
#include "fatfs/osal_file.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "lib/multimedia/msi.h"
#include "osal/string.h"
#include "stream_define.h"
#include "audio_media_ctrl/audio_code_ctrl.h"
#include "audio_msi/audio_adc.h"
#include "app/video_app/file_thumb.h"
#include "app/recorder/file_process.h"
#ifdef PIN_FROM_PARAM
#include "pin_param.h"
#endif
#include "stream_define.h"
#include "mp4/mp4_encode.h"
// data 申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
// 结构体申请空间函数
#define STREAM_LIBC_MALLOC os_malloc
#define STREAM_LIBC_FREE os_free
#define STREAM_LIBC_ZALLOC os_zalloc
#define MP4_TIMELAPSE_TIME 40
#define AVERAGE_BASE 6
#define MP4_VIDEO_FPS 25U
#define MP4_AUDIO_FPS 8U // 实际为 8000Hz/1024≈7.8 约为128ms一帧
#define MP4_FRAME_COUNT(fps, ms) (((fps) * (ms) + 999U) / 1000U)
// 预录时间及缓冲区大小
#define MP4_EVENT_PRERECORD_MS 3000U
#define MP4_EVENT_BUFFER_MARGIN_MS 1000U
#define MP4_EVENT_BUFFER_MAX_MS (MP4_EVENT_PRERECORD_MS + MP4_EVENT_BUFFER_MARGIN_MS)
#define MP4_EVENT_BUFFER_VIDEO_COUNT MP4_FRAME_COUNT(MP4_VIDEO_FPS, MP4_EVENT_BUFFER_MAX_MS)
#define MP4_EVENT_BUFFER_AUDIO_COUNT MP4_FRAME_COUNT(MP4_AUDIO_FPS, MP4_EVENT_BUFFER_MAX_MS)
#define MP4_EVENT_BUFFER_MAX_COUNT (MP4_EVENT_BUFFER_VIDEO_COUNT + MP4_EVENT_BUFFER_AUDIO_COUNT)
// 普通模式录卡缓冲区大小 2.5s
#define MP4_MAX_VIDEO_EXTRA_COUNT MP4_FRAME_COUNT(MP4_VIDEO_FPS, 2500)
#define MP4_MAX_AUDIO_EXTRA_COUNT MP4_FRAME_COUNT(MP4_VIDEO_FPS, 2500)
#define MP4_VIDEO_I_EXTRA_COUNT 12U // 缓冲区不足时只接收 I 帧
#define MP4_MAX_VIDEO_COUNT_NORMAL MP4_MAX_VIDEO_EXTRA_COUNT
#define MP4_MAX_AUDIO_COUNT_NORMAL MP4_MAX_AUDIO_EXTRA_COUNT
#define MP4_MAX_COUNT_NORMAL (MP4_MAX_VIDEO_COUNT_NORMAL + MP4_MAX_AUDIO_COUNT_NORMAL + MP4_VIDEO_I_EXTRA_COUNT)
#define MP4_MAX_VIDEO_COUNT_EVENT (MP4_EVENT_BUFFER_VIDEO_COUNT + MP4_MAX_VIDEO_EXTRA_COUNT)
#define MP4_MAX_AUDIO_COUNT_EVENT (MP4_EVENT_BUFFER_AUDIO_COUNT + MP4_MAX_AUDIO_EXTRA_COUNT)
#define MP4_MAX_COUNT_EVENT (MP4_MAX_VIDEO_COUNT_EVENT + MP4_MAX_AUDIO_COUNT_EVENT + MP4_VIDEO_I_EXTRA_COUNT)
#ifndef MAX_SINGLE_MP4_SIZE
#define MAX_SINGLE_MP4_SIZE (100 * 1024 * 1024)
#endif
enum
{
MSI_MP4_START = BIT(0),
MSI_MP4_STOP = BIT(1),
MSI_MP4_THREAD_DEAD = BIT(2),
MSI_MP4_EVENT_START = BIT(3),
MSI_MP4_EVENT_STOP = BIT(4),
};
enum
{
MP4_ENCODE_ERR_NONE,
MP4_ENCODE_ERR_STOP,
MP4_ENCODE_ERR_EVENT_STOP,
MP4_ENCODE_ERR_NO_SD,
};
// 录制模式
enum
{
MP4_MODE_NORMAL, // 普通录像模式
MP4_MODE_TIME_LAPSE, // 缩时录影模式
MP4_MODE_EVETN, // 事件录像模式
};
struct mp4_event_buffer_s
{
struct framebuff *frames[MP4_EVENT_BUFFER_MAX_COUNT];
uint16_t head;
uint16_t tail;
uint16_t count;
uint32_t latest_time;
};
struct mp4_event_ctx_s
{
uint32_t trigger_time;
struct mp4_event_buffer_s event_buffer;
};
struct mp4_encode_msi_s
{
struct msi *msi;
struct os_event evt;
struct file_process file_process;
struct mp4_event_ctx_s *event;
void *fb;
uint8_t filter_type;
uint8_t srcID;
uint8_t mode; // 普通录像 / 缩时录影 / 事件触发
int16_t max_video_count;
uint32_t rec_time;
uint32_t rec_second;
uint32_t audio_encode;
uint32_t timeLapse_count;
uint32_t file_size;
};
extern struct msi *mp4_thumb_msi_init(const char *filename, uint8_t srcID, uint8_t filter);
static int mp4_is_event_mode(const struct mp4_encode_msi_s *mp4_encode)
{
return mp4_encode->mode == MP4_MODE_EVETN && mp4_encode->event != NULL;
}
static uint16_t mp4_msi_queue_count(uint8_t mode)
{
if (mode == MP4_MODE_EVETN)
{
return MP4_MAX_COUNT_EVENT;
}
return MP4_MAX_COUNT_NORMAL;
}
static int16_t mp4_max_video_count_limit(const struct mp4_encode_msi_s *mp4_encode)
{
return mp4_is_event_mode(mp4_encode) ? MP4_MAX_VIDEO_COUNT_EVENT : MP4_MAX_VIDEO_COUNT_NORMAL;
}
static int mp4_is_realtime_mode(const struct mp4_encode_msi_s *mp4_encode)
{
return mp4_encode->mode != MP4_MODE_TIME_LAPSE;
}
static int mp4_has_audio(const struct mp4_encode_msi_s *mp4_encode)
{
return mp4_is_realtime_mode(mp4_encode) && mp4_encode->audio_encode == AAC_ENC;
}
static const char *mp4_mode_str(const struct mp4_encode_msi_s *mp4_encode)
{
if (mp4_encode->mode == MP4_MODE_TIME_LAPSE)
{
return "TIME_LAPSE";
}
if (mp4_encode->mode == MP4_MODE_EVETN)
{
return "EVENT";
}
return "NORMAL";
}
static void mp4_event_buffer_drop_head(struct mp4_encode_msi_s *mp4_encode)
{
struct mp4_event_ctx_s *event = mp4_encode->event;
struct mp4_event_buffer_s *event_buffer;
struct framebuff *fb;
if (event == NULL)
{
return;
}
event_buffer = &event->event_buffer;
if (event_buffer->count == 0)
{
return;
}
fb = event_buffer->frames[event_buffer->head];
event_buffer->frames[event_buffer->head] = NULL;
event_buffer->head = (event_buffer->head + 1) % MP4_EVENT_BUFFER_MAX_COUNT;
event_buffer->count--;
if (event_buffer->count == 0)
{
event_buffer->tail = 0;
event_buffer->head = 0;
event_buffer->latest_time = 0;
}
if (fb)
{
msi_delete_fb(NULL, fb);
}
}
static void mp4_event_buffer_reset(struct mp4_encode_msi_s *mp4_encode)
{
struct mp4_event_ctx_s *event = mp4_encode->event;
if (event == NULL)
{
return;
}
while (event->event_buffer.count)
{
mp4_event_buffer_drop_head(mp4_encode);
}
}
static struct framebuff *mp4_event_buffer_first(const struct mp4_encode_msi_s *mp4_encode)
{
const struct mp4_event_ctx_s *event = mp4_encode->event;
if (event == NULL || event->event_buffer.count == 0)
{
return NULL;
}
return event->event_buffer.frames[event->event_buffer.head];
}
static struct framebuff *mp4_event_buffer_pop(struct mp4_encode_msi_s *mp4_encode)
{
struct mp4_event_ctx_s *event = mp4_encode->event;
struct mp4_event_buffer_s *event_buffer;
struct framebuff *fb;
if (event == NULL)
{
return NULL;
}
event_buffer = &event->event_buffer;
if (event_buffer->count == 0)
{
return NULL;
}
fb = event_buffer->frames[event_buffer->head];
event_buffer->frames[event_buffer->head] = NULL;
event_buffer->head = (event_buffer->head + 1) % MP4_EVENT_BUFFER_MAX_COUNT;
event_buffer->count--;
if (event_buffer->count == 0)
{
event_buffer->tail = 0;
event_buffer->head = 0;
event_buffer->latest_time = 0;
}
return fb;
}
static void mp4_event_buffer_push(struct mp4_encode_msi_s *mp4_encode, struct framebuff *fb)
{
struct mp4_event_ctx_s *event = mp4_encode->event;
struct mp4_event_buffer_s *event_buffer;
struct framebuff *first_fb;
if (event == NULL || fb == NULL)
{
return;
}
event_buffer = &event->event_buffer;
while (event_buffer->count >= MP4_EVENT_BUFFER_MAX_COUNT)
{
mp4_event_buffer_drop_head(mp4_encode);
}
event_buffer->frames[event_buffer->tail] = fb;
event_buffer->tail = (event_buffer->tail + 1) % MP4_EVENT_BUFFER_MAX_COUNT;
event_buffer->count++;
event_buffer->latest_time = fb->time;
while (event_buffer->count)
{
first_fb = mp4_event_buffer_first(mp4_encode);
if (first_fb == NULL)
{
mp4_event_buffer_drop_head(mp4_encode);
continue;
}
if (event_buffer->latest_time < first_fb->time)
{
break;
}
if (event_buffer->latest_time - first_fb->time <= MP4_EVENT_BUFFER_MAX_MS)
{
break;
}
mp4_event_buffer_drop_head(mp4_encode);
}
}
static int mp4_event_buffer_prepare(struct mp4_encode_msi_s *mp4_encode)
{
struct mp4_event_ctx_s *event = mp4_encode->event;
struct mp4_event_buffer_s *event_buffer;
uint32_t target_time = 0;
int32_t first_i_off = -1;
int32_t start_off = -1;
uint16_t i;
if (event == NULL)
{
return RET_ERR;
}
event_buffer = &event->event_buffer;
if (event_buffer->count == 0)
{
return RET_ERR;
}
if (event->trigger_time > MP4_EVENT_PRERECORD_MS)
{
target_time = event->trigger_time - MP4_EVENT_PRERECORD_MS;
}
for (i = 0; i < event_buffer->count; i++)
{
struct framebuff *fb = event_buffer->frames[(event_buffer->head + i) % MP4_EVENT_BUFFER_MAX_COUNT];
struct fb_h264_s *priv;
if (!fb || fb->mtype != F_H264)
{
continue;
}
priv = (struct fb_h264_s *) fb->priv;
if (priv && priv->type == 1)
{
if (first_i_off < 0)
{
first_i_off = i;
}
if (fb->time <= target_time)
{
start_off = i;
}
}
}
if (start_off < 0)
{
start_off = first_i_off;
}
if (start_off < 0)
{
return RET_ERR;
}
while (start_off-- > 0)
{
mp4_event_buffer_drop_head(mp4_encode);
}
while (event_buffer->count)
{
struct framebuff *fb = mp4_event_buffer_first(mp4_encode);
if (fb && fb->mtype == F_H264)
{
return RET_OK;
}
mp4_event_buffer_drop_head(mp4_encode);
}
return RET_ERR;
}
static struct framebuff *mp4_get_next_fb(struct msi *msi)
{
struct mp4_encode_msi_s *mp4_encode = (struct mp4_encode_msi_s *) msi->priv;
struct framebuff *fb = NULL;
if (mp4_is_event_mode(mp4_encode))
{
fb = mp4_event_buffer_pop(mp4_encode);
}
if (fb == NULL)
{
fb = msi_get_fb(msi, 0);
if (fb && (fb->mtype == F_H264))
{
mp4_encode->max_video_count--;
}
}
return fb;
}
static int mp4_event_wait_record_start(struct msi *msi)
{
struct mp4_encode_msi_s *mp4_encode = (struct mp4_encode_msi_s *) msi->priv;
struct mp4_event_ctx_s *event = mp4_encode->event;
if (event == NULL)
{
return MP4_ENCODE_ERR_STOP;
}
while (1)
{
struct framebuff *fb = NULL;
uint32_t mp4_status = 0;
os_event_wait(&mp4_encode->evt, MSI_MP4_STOP | MSI_MP4_EVENT_STOP | MSI_MP4_EVENT_START, &mp4_status, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, 0);
if (mp4_status & MSI_MP4_STOP)
{
_os_printf("%s %d\r\n", __func__, __LINE__);
return MP4_ENCODE_ERR_STOP;
}
if (mp4_status & MSI_MP4_EVENT_STOP)
{
event->trigger_time = 0;
continue;
}
if (mp4_status & MSI_MP4_EVENT_START)
{
if (event->event_buffer.count)
{
event->trigger_time = event->event_buffer.latest_time;
}
else
{
event->trigger_time = os_jiffies();
}
if (mp4_event_buffer_prepare(mp4_encode) == RET_OK)
{
_os_printf("%s %d\r\n", __func__, __LINE__);
return MP4_ENCODE_ERR_NONE;
}
}
if(mp4_encode->fb)
{
fb = mp4_encode->fb;
mp4_encode->max_video_count++;
mp4_encode->fb = NULL;
}
else
{
fb = msi_get_fb(msi, 0);
}
if (fb)
{
if (fb->mtype == F_H264)
{
mp4_encode->max_video_count--;
}
if (fb->mtype == F_H264 || (fb->mtype == F_AUDIO && mp4_has_audio(mp4_encode)))
{
mp4_event_buffer_push(mp4_encode, fb);
}
else
{
msi_delete_fb(NULL, fb);
}
}
if (event->trigger_time && mp4_event_buffer_prepare(mp4_encode) == RET_OK)
{
_os_printf("%s %d\r\n", __func__, __LINE__);
return MP4_ENCODE_ERR_NONE;
}
os_sleep_ms(1); // 任务调度
}
}
static uint32_t a2i(char *str)
{
uint32_t ret = 0;
uint32_t indx = 0;
char str_buf[32];
memset(str_buf, 0, 32);
while (str[indx] != '\0')
{
if (str[indx] == '.')
{
break;
}
str_buf[indx] = str[indx];
indx++;
}
// printf("str_buf:%s str:%s\r\n",str_buf,str);
indx = 0;
while (str_buf[indx] != '\0')
{
if (str_buf[indx] >= '0' && str_buf[indx] <= '9')
{
ret = ret * 10 + str_buf[indx] - '0';
}
indx++;
}
return ret;
}
static void get_aac_config(uint32_t samplerate, uint8_t *config_buf)
{
uint8_t samplerate_index = 0;
switch (samplerate)
{
case 48000:
samplerate_index = 0x3;
break;
case 44100:
samplerate_index = 0x4;
break;
case 36000:
samplerate_index = 0x5;
break;
case 24000:
samplerate_index = 0x6;
break;
case 22050:
samplerate_index = 0x7;
break;
case 16000:
samplerate_index = 0x8;
break;
case 12000:
samplerate_index = 0x9;
break;
case 11025:
samplerate_index = 0xA;
break;
case 8000:
samplerate_index = 0xB;
break;
default:
break;
}
config_buf[0] = (0x02 << 3) | (samplerate_index >> 1);
config_buf[1] = ((samplerate_index & 0x1) << 7) | (0x01 << 3);
}
// 获取nal的size,从0开始搜索,返回的是的nal头的size,offset相对于头的偏移(通过多次调用,可以用于计算nal_size)
// 返回0代表搜索不到nal的头
static uint8_t get_nal_size(uint8_t *buf, uint32_t size, uint32_t *offset)
{
uint32_t pos = 0;
while ((size - pos) > 3)
{
if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 1)
{
*offset = pos;
return 3;
}
if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 0 && buf[pos + 3] == 1)
{
*offset = pos;
return 4;
}
pos++;
}
return 0;
}
// 只是获取pps和sps的nalsize
static uint8_t *get_sps_pps_nal_size(uint8_t *buf, uint32_t size, uint32_t *nal_size, uint8_t *head_size)
{
uint32_t offset;
uint8_t nal_head_size = get_nal_size(buf, size, &offset);
uint8_t nal_type;
uint8_t *ret_buf = NULL;
// 找到头部,检查类型
if (nal_head_size && offset + nal_head_size < size)
{
nal_type = buf[nal_head_size + offset] & 0x1f;
// 找到sps和pps就返回长度和偏移(相对buf的偏移)
if (nal_type == 7 || nal_type == 8)
{
// 查找下一个nal
nal_head_size = get_nal_size(buf + offset + nal_head_size, size - (offset + nal_head_size), nal_size);
if (nal_head_size)
{
// 偏移到nal的头部
ret_buf = buf + offset;
// 返回nal的头size
*head_size = nal_head_size;
}
}
}
return ret_buf;
}
static int mp4_encode_running(struct msi *msi, uint32_t save_time, void *fp, const char *h264_filename, uint32_t filesize)
{
int ret = MP4_ENCODE_ERR_NONE;
struct mp4_encode_msi_s *mp4_encode = (struct mp4_encode_msi_s *) msi->priv;
struct framebuff *fb = mp4_encode->fb; // 获取缓冲的一帧数据
mp4_encode->fb = NULL;
struct msi *mp4_thumb_msi = NULL;
void *mp4_msg = NULL;
int32_t error = 0;
uint32_t MP4_status = 0;
uint32_t write_start_time = os_jiffies();
uint32_t nal_size;
uint8_t nal_head_size;
uint8_t *buf;
uint8_t *nal_head_buf;
uint8_t *last_nal_head_buf;
uint8_t sps_pps_flag = 0;
uint8_t h264_count = 0;
uint8_t asps_data[2];
uint32_t now_time = 0;
uint32_t last_fb_time = 0;
uint32_t video_first_time = 0;
uint32_t audio_first_time = 0;
uint32_t second = 0;
uint32_t last_adjust_pts_time = os_jiffies();
int delta = 40;
int average_pts = delta * 90;
int acc_pts = 0;
int acc_pts_tmp = 0;
int write_size = 0;
uint32_t v_count = 0;
os_printf(KERN_DEBUG "max_video_count: %d, mode: %s\r\n", mp4_encode->max_video_count, mp4_mode_str(mp4_encode));
if (!fp)
{
os_sleep_ms(1);
ret = MP4_ENCODE_ERR_NO_SD;
goto mp4_encode_running_clean_end;
}
// 根据模式决定是否包含音频
int has_audio = mp4_has_audio(mp4_encode);
mp4_msg = MP4_open_init((F_FILE *) fp, has_audio);
if (!mp4_msg)
{
goto mp4_encode_running_clean_end;
}
// 配置音频和视频
if (has_audio)
{
get_aac_config(audio_adc_get_samplerate(AUSYS_AUAD), asps_data);
mp4_audio_cfg_init(mp4_msg, asps_data, sizeof(asps_data));
}
mp4_set_max_size(mp4_msg, filesize);
// mp4_video_cfg_init(mp4_msg, 1280, 720);
// 初始化PTS相关变量
if (mp4_is_realtime_mode(mp4_encode))
{
acc_pts = (delta * 90);
}
// 启动缩略图生成
mp4_thumb_msi = mp4_thumb_msi_init(h264_filename, FRAMEBUFF_SOURCE_CAMERA0, FSTYPE_NONE);
msi->enable = 1;
while (fp)
{
os_event_wait(&mp4_encode->evt, MSI_MP4_STOP | MSI_MP4_EVENT_STOP, &MP4_status, OS_EVENT_WMODE_OR, 0);
// 结束写卡
if (MP4_status & MSI_MP4_STOP)
{
ret = MP4_ENCODE_ERR_STOP;
goto mp4_encode_running_clean_end;
}
if (mp4_is_event_mode(mp4_encode) && (MP4_status & MSI_MP4_EVENT_STOP))
{
ret = MP4_ENCODE_ERR_EVENT_STOP;
goto mp4_encode_running_event_end;
}
if (fb == NULL)
{
fb = mp4_get_next_fb(msi);
}
if (fb && (fb->mtype == F_H264))
{
struct fb_h264_s *h264_priv = (struct fb_h264_s *) fb->priv;
// 帧序号检查和PTS计算
if (mp4_is_realtime_mode(mp4_encode))
{
// 检查录制时间
if (video_first_time != 0 && fb->time >= video_first_time && fb->time - video_first_time >= save_time)
{
if (h264_priv->type == 1)
{
mp4_encode->fb = fb;
if (mp4_is_event_mode(mp4_encode))
{
goto mp4_encode_running_event_end;
}
goto mp4_encode_running_end;
}
}
// 超时退出 3s
if (os_jiffies() - write_start_time >= save_time + 3000)
{
if (mp4_is_event_mode(mp4_encode))
{
goto mp4_encode_running_event_end;
}
goto mp4_encode_running_clean_end;
}
h264_count++;
if ((h264_priv->count != h264_count) && (h264_priv->type != 1))
{
os_printf(KERN_ERR "%s: %d h264 frame lost,count: %d,expect: %d\ttype: %d\n", __FUNCTION__, __LINE__, h264_priv->count, h264_count, h264_priv->type);
goto mp4_encode_running_no_found_sps_pps;
}
h264_count = h264_priv->count;
// PTS计算和调整
if (last_fb_time == 0)
{
last_fb_time = fb->time;
}
else
{
average_pts += ((((fb->time - last_fb_time) * 90) >> AVERAGE_BASE) - (average_pts >> AVERAGE_BASE));
}
if (now_time == 0)
{
now_time = fb->time;
video_first_time = fb->time;
}
acc_pts += ((fb->time - last_fb_time) * 90);
acc_pts -= (delta * 90);
acc_pts_tmp = acc_pts > 0 ? acc_pts : -acc_pts;
if (acc_pts_tmp / average_pts)
{
if (os_jiffies() - last_adjust_pts_time > 1000)
{
delta = (average_pts + (acc_pts / 60)) / 90;
last_adjust_pts_time = os_jiffies();
}
}
if (os_jiffies() - last_adjust_pts_time > 5000)
{
last_adjust_pts_time = os_jiffies();
delta = (average_pts) / 90;
}
last_fb_time = fb->time;
}
else
{
if (mp4_encode->timeLapse_count <= v_count)
{
goto mp4_encode_running_clean_end;
}
v_count++;
}
buf = fb->data;
nal_head_size = 0;
nal_head_buf = buf;
last_nal_head_buf = nal_head_buf;
mp4_encode_running_again:
// 检查是否存在pps或者sps
nal_head_buf = get_sps_pps_nal_size(nal_head_buf, 64, &nal_size, &nal_head_size);
// 找到pps或者sps
if (nal_head_buf)
{
// 重置写入时间
if (!sps_pps_flag && mp4_is_realtime_mode(mp4_encode))
{
write_start_time = os_jiffies();
}
mp4_video_cfg_init(mp4_msg, h264_priv->w, h264_priv->h);
error |= write_h264_pps_sps(mp4_msg, nal_head_buf, nal_size + nal_head_size);
if (0 != error)
{
os_printf(KERN_ERR "%s:%d\n", __FUNCTION__, __LINE__);
if (mp4_is_event_mode(mp4_encode))
{
goto mp4_encode_running_event_clean_end;
}
goto mp4_encode_running_clean_end;
}
nal_head_buf += (nal_size + nal_head_size);
last_nal_head_buf = nal_head_buf;
sps_pps_flag = 1;
goto mp4_encode_running_again;
}
// 如果没有写过sps和pps就跳过
if (!sps_pps_flag)
{
now_time = 0;
video_first_time = 0;
goto mp4_encode_running_no_found_sps_pps;
}
// 写剩余的nal数据
if (!mp4_is_realtime_mode(mp4_encode))
{
_os_printf(KERN_INFO "T");
error |= write_h264_data(mp4_msg, last_nal_head_buf, fb->len - (last_nal_head_buf - fb->data), MP4_TIMELAPSE_TIME);
write_size += (fb->len - (last_nal_head_buf - fb->data));
}
else
{
_os_printf(KERN_INFO "M");
error |= write_h264_data(mp4_msg, last_nal_head_buf, fb->len - (last_nal_head_buf - fb->data), delta);
}
if (0 != error)
{
os_printf(KERN_ERR "%s: %d\n", __FUNCTION__, __LINE__);
if (mp4_is_event_mode(mp4_encode))
{
goto mp4_encode_running_event_clean_end;
}
goto mp4_encode_running_clean_end;
}
now_time = fb->time;
mp4_encode_running_no_found_sps_pps:
msi_delete_fb(NULL, fb);
fb = NULL;
if (!mp4_is_realtime_mode(mp4_encode))
{
// 每帧立即同步
error |= mp4_syn(mp4_msg);
if (0 != error)
{
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
if (mp4_is_event_mode(mp4_encode))
{
goto mp4_encode_running_event_clean_end;
}
goto mp4_encode_running_clean_end;
}
}
else
{
// 每秒同步一次
if ((now_time - video_first_time) / 1000 > second)
{
second = (now_time - video_first_time) / 1000;
mp4_encode->rec_second = second;
os_printf(KERN_DEBUG "save second: %d\n", second);
#if 1
error |= mp4_syn(mp4_msg);
if (0 != error)
{
os_printf(KERN_ERR "%s:%d\n", __FUNCTION__, __LINE__);
if (mp4_is_event_mode(mp4_encode))
{
goto mp4_encode_running_event_clean_end;
}
goto mp4_encode_running_clean_end;
}
#endif
}
}
}
else if (sps_pps_flag && fb && (fb->mtype == F_AUDIO) && has_audio)
{
if (audio_first_time == 0)
{
if (video_first_time != 0 && fb->time >= video_first_time)
{
audio_first_time = fb->time;
}
else
{
_os_printf("P");
// 音频时间不对,直接删除
msi_delete_fb(NULL, fb);
fb = NULL;
continue;
}
}
buf = fb->data;
_os_printf("U");
error |= write_aac_data(mp4_msg, buf + 7, fb->len - 7, 128);
if (0 != error)
{
if (mp4_is_event_mode(mp4_encode))
{
goto mp4_encode_running_event_clean_end;
}
goto mp4_encode_running_clean_end;
}
msi_delete_fb(NULL, fb);
fb = NULL;
}
else
{
msi_delete_fb(NULL, fb);
fb = NULL;
}
os_sleep_ms(1);
}
mp4_encode_running_clean_end:
if (fb)
{
msi_delete_fb(NULL, fb);
fb = NULL;
}
// 清空缓冲区
msi->enable = 0;
while (1)
{
fb = msi_get_fb(msi, 0);
if (fb)
{
msi_delete_fb(NULL, fb);
}
else
{
break;
}
}
mp4_encode_running_event_clean_end:
if (fb)
{
msi_delete_fb(NULL, fb);
fb = NULL;
}
mp4_encode_running_event_end:
// 清空预录缓冲区
if (mp4_is_event_mode(mp4_encode))
{
while(1)
{
fb = mp4_event_buffer_pop(mp4_encode);
if(fb)
{
msi_delete_fb(NULL, fb);
}
else
{
break;
}
}
}
mp4_encode_running_end:
mp4_encode->rec_second = 0;
if (mp4_msg)
{
mp4_deinit(mp4_msg);
}
if (fp)
{
osal_fclose(fp);
fp = NULL;
}
if (mp4_thumb_msi)
{
msi_destroy(mp4_thumb_msi);
}
if (error)
{
os_printf(KERN_ERR "mp4 encode error: %d\n", error);
}
os_printf(KERN_DEBUG "mp4 encode end, mode: %s\n", mp4_mode_str(mp4_encode));
return ret;
}
static void mp4_encode_thread(void *d)
{
int ret = 0;
uint32_t mp4_status = 0;
struct msi *msi = (struct msi *) d;
struct mp4_encode_msi_s *mp4_encode = (struct mp4_encode_msi_s *) msi->priv;
struct file_process *file_process = &mp4_encode->file_process;
void *fp = NULL;
uint32_t filesize = 0;
char filename[64];
char filepath[64];
msi_get(msi);
os_event_wait(&mp4_encode->evt, MSI_MP4_START | MSI_MP4_STOP, &mp4_status, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, -1);
if (mp4_status & MSI_MP4_STOP)
{
goto mp4_encode_thread_end;
}
while (msi)
{
filesize = ((mp4_encode->rec_time / 60) + (mp4_encode->rec_time % 60 ? 1 : 0)) * mp4_encode->file_size;
if (mp4_is_event_mode(mp4_encode))
{
msi->enable = 1;
ret = mp4_event_wait_record_start(msi);
if (ret == MP4_ENCODE_ERR_STOP)
{
break;
}
struct framebuff *first_fb = NULL;
first_fb = mp4_event_buffer_first(mp4_encode);
file_process->frame_time = first_fb ? first_fb->time : 0;
}
if (file_process->create_file)
{
if (!mp4_is_event_mode(mp4_encode) && mp4_encode->fb)
{
struct framebuff *fb = mp4_encode->fb;
file_process->frame_time = fb->time;
}
fp = file_process->create_file(file_process, filename, filepath, filesize);
}
// 如果时缩时录影寻找到I帧再继续录制这里需要发送一个命令强行产生一帧I帧
if(file_process->start_encode)
{
file_process->param = mp4_encode->mode;
file_process->start_encode(file_process);
}
ret = mp4_encode_running(msi, mp4_encode->rec_time * 1000, fp, filename, filesize);
if (file_process->lock_file && ret != MP4_ENCODE_ERR_NO_SD)
{
file_process->lock_file(filename, filepath);
}
if(file_process->end_encode)
{
file_process->param = ret;
file_process->end_encode(file_process);
}
os_printf(KERN_DEBUG "%s %d end\n", __FUNCTION__, __LINE__);
if (mp4_is_event_mode(mp4_encode))
{
mp4_encode->event->trigger_time = 0;
mp4_event_buffer_reset(mp4_encode);
os_event_clear(&mp4_encode->evt, MSI_MP4_EVENT_START, NULL);
os_event_clear(&mp4_encode->evt, MSI_MP4_EVENT_STOP, NULL);
if (ret == MP4_ENCODE_ERR_STOP)
{
break;
}
if (ret == MP4_ENCODE_ERR_EVENT_STOP)
{
os_printf("mp4 event stop\n");
}
if (ret == MP4_ENCODE_ERR_NO_SD && file_process->loop_free)
{
file_process->loop_free(&file_process->loop);
}
os_printf(KERN_DEBUG "%s %d end, ret: %d\n", __FUNCTION__, __LINE__, ret);
continue;
}
if (ret)
{
if (file_process->loop_free)
{
file_process->loop_free(&file_process->loop);
}
// 如果是sd异常,延迟1s然后重新尝试重新录像(同时检测是否要停止)
if (ret == MP4_ENCODE_ERR_NO_SD)
{
mp4_status = 0;
os_event_wait(&mp4_encode->evt, MSI_MP4_STOP, &mp4_status, OS_EVENT_WMODE_OR, 1000);
if (mp4_status & MSI_MP4_STOP)
{
break;
}
}
else
{
break;
}
}
os_printf(KERN_DEBUG "%s %d end, ret: %d\n", __FUNCTION__, __LINE__, ret);
}
mp4_encode_thread_end:
if (mp4_is_event_mode(mp4_encode))
{
mp4_encode->event->trigger_time = 0;
mp4_event_buffer_reset(mp4_encode);
}
os_event_set(&mp4_encode->evt, MSI_MP4_THREAD_DEAD, NULL);
msi_put(msi);
os_printf(KERN_DEBUG "%s: %d end\n", __FUNCTION__, __LINE__);
}
static int32_t MP4_encode_msi_action(struct msi *msi, uint32_t cmd_id, uint32_t param1, uint32_t param2)
{
int32_t ret = RET_OK;
struct mp4_encode_msi_s *mp4_encode = (struct mp4_encode_msi_s *) msi->priv;
switch (cmd_id)
{
case MSI_CMD_POST_DESTROY:
os_event_wait(&mp4_encode->evt, MSI_MP4_THREAD_DEAD, NULL, OS_EVENT_WMODE_OR | OS_EVENT_WMODE_CLEAR, -1);
if (mp4_is_event_mode(mp4_encode))
{
mp4_encode->event->trigger_time = 0;
mp4_event_buffer_reset(mp4_encode);
}
if (mp4_encode->fb)
{
msi_delete_fb(NULL, (struct framebuff *) mp4_encode->fb);
mp4_encode->fb = NULL;
}
if (mp4_encode->event)
{
STREAM_LIBC_FREE(mp4_encode->event);
mp4_encode->event = NULL;
}
os_event_del(&mp4_encode->evt);
STREAM_LIBC_FREE(mp4_encode);
break;
case MSI_CMD_PRE_DESTROY:
os_event_set(&mp4_encode->evt, MSI_MP4_STOP, NULL);
break;
case MSI_CMD_TRANS_FB:
{
struct framebuff *fb = (struct framebuff *) param1;
// 暂时接收所有的音频
if (fb->mtype == F_AUDIO)
{
// 缩时录影不接收音频
if (mp4_encode->mode == MP4_MODE_TIME_LAPSE)
{
ret = RET_ERR;
}
}
else if (fb->mtype == F_H264 && mp4_encode->filter_type != (uint16_t) ~0)
{
if (mp4_encode->srcID != 0 && fb->srcID != mp4_encode->srcID)
{
ret = RET_ERR;
break;
}
ret = RET_ERR;
if (mp4_encode->filter_type == fb->stype)
{
ret = RET_OK;
}
// 帧选择策略
if (ret == RET_OK)
{
// 缓冲区满时只接收I帧
if (mp4_encode->max_video_count > mp4_max_video_count_limit(mp4_encode))
{
struct fb_h264_s *priv = (struct fb_h264_s *) fb->priv;
if (priv->type != 1)
{
ret = RET_ERR;
os_printf(KERN_ERR "h264 drop: %d\n", mp4_encode->max_video_count);
}
}
}
if (ret == RET_OK)
{
mp4_encode->max_video_count++;
}
}
}
break;
case MSI_CMD_GET_RUNNING:
{
uint32_t rflags = 0;
os_event_wait(&mp4_encode->evt, MSI_MP4_THREAD_DEAD | MSI_MP4_STOP, &rflags, OS_EVENT_WMODE_OR, 0);
if (param1)
{
*(uint32_t *) param1 = (rflags & (MSI_MP4_THREAD_DEAD | MSI_MP4_STOP)) ? 0 : 1;
}
}
break;
case MSI_CMD_MEDIA_CTRL:
{
uint32_t cmd_self = (uint32_t) param1;
uint32_t arg = (uint32_t) param2;
switch (cmd_self)
{
case MSI_MEDIA_CTRL_GET_RECTIME:
{
*(uint32_t *) arg = mp4_encode->rec_second;
}
break;
case MSI_MEDIA_CTRL_RECORD_START:
{
os_event_set(&mp4_encode->evt, MSI_MP4_START, NULL);
}
break;
case MSI_MEDIA_CTRL_SET_RECORD_SIZE:
{
mp4_encode->file_size = arg;
}
break;
case MSI_MEDIA_CTRL_SET_RECORD_SEC:
{
mp4_encode->rec_time = arg;
mp4_encode->timeLapse_count = arg * (1000 / MP4_TIMELAPSE_TIME);
}
break;
case MSI_MEDIA_CTRL_EVENT_START:
{
if (mp4_is_event_mode(mp4_encode))
{
os_event_set(&mp4_encode->evt, MSI_MP4_EVENT_START, NULL);
}
}
break;
case MSI_MEDIA_CTRL_EVENT_STOP:
{
if (mp4_is_event_mode(mp4_encode))
{
os_event_set(&mp4_encode->evt, MSI_MP4_EVENT_STOP, NULL);
}
}
break;
}
}
break;
}
return ret;
}
struct msi *mp4_encode_msi2_init(const char *mp4_msi_name, uint8_t srcID, uint8_t filter_type, uint8_t rec_time,
uint32_t audio_encode, struct file_process *file_process, uint8_t mode)
{
uint8_t is_new = 0;
struct mp4_encode_msi_s *mp4_encode = NULL;
struct msi *msi = msi_new(mp4_msi_name, mp4_msi_queue_count(mode), &is_new);
if (is_new)
{
mp4_encode = (struct mp4_encode_msi_s *) STREAM_LIBC_ZALLOC(sizeof(struct mp4_encode_msi_s));
ASSERT(mp4_encode);
mp4_encode->filter_type = filter_type;
mp4_encode->srcID = srcID;
mp4_encode->rec_time = rec_time * 60;
mp4_encode->mode = mode; // 设置录制模式
mp4_encode->timeLapse_count = rec_time * 60 * (1000 / MP4_TIMELAPSE_TIME);
mp4_encode->file_size = MAX_SINGLE_MP4_SIZE;
if (mode == MP4_MODE_EVETN)
{
mp4_encode->event = (struct mp4_event_ctx_s *) STREAM_LIBC_ZALLOC(sizeof(struct mp4_event_ctx_s));
if (mp4_encode->event == NULL)
{
STREAM_LIBC_FREE(mp4_encode);
mp4_encode = NULL;
if (msi)
{
msi_destroy(msi);
msi = NULL;
}
goto mp4_encode_msi_init_end;
}
}
if (file_process == NULL)
{
// 配置默认值
mp4_encode->file_process.rec_path = REC_PATH;
mp4_encode->file_process.ext_name = MP4_EXTENSION_NAME;
mp4_encode->file_process.create_file = rec_create_file;
mp4_encode->file_process.loop_free = rec_loop_free;
}
else
{
os_memcpy(&mp4_encode->file_process, file_process, sizeof(struct file_process));
}
if (mode == MP4_MODE_TIME_LAPSE)
{
// 缩时录影无音频
mp4_encode->audio_encode = 0;
}
else
{
mp4_encode->audio_encode = audio_encode;
}
os_event_init(&mp4_encode->evt);
mp4_encode->msi = msi;
msi->priv = mp4_encode;
msi->action = MP4_encode_msi_action;
msi->enable = 1;
}
else
{
if (msi)
{
msi_destroy(msi);
msi = NULL;
}
goto mp4_encode_msi_init_end;
}
void *mp4_hdl = os_task_create("mp4_encode", mp4_encode_thread, msi, OS_TASK_PRIORITY_ABOVE_NORMAL, 0, NULL, 2048);
os_printf(KERN_DEBUG "mp4_hdl: %x\n", mp4_hdl);
if (!mp4_hdl && mp4_encode)
{
os_event_set(&mp4_encode->evt, MSI_MP4_THREAD_DEAD, NULL);
}
mp4_encode_msi_init_end:
return msi;
}