1341 lines
40 KiB
C
1341 lines
40 KiB
C
#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;
|
||
}
|
||
|