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

1341 lines
40 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}