Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources
This commit is contained in:
148
sdk/lib/video/miniMP4/adts.c
Normal file
148
sdk/lib/video/miniMP4/adts.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @file adts.c
|
||||
* @brief
|
||||
* @author licaibiao
|
||||
* @version 1.0
|
||||
* @date 2023-12-06
|
||||
*
|
||||
* @copyright Copyright (c) 2023-2030 liwen01 Technology Co., Ltd
|
||||
*
|
||||
*/
|
||||
#include "adts.h"
|
||||
#include <math.h>
|
||||
|
||||
void set_fixed_header(adts_fixed_header *header) {
|
||||
header->syncword = 0xFF;// 代表着一个帧的开始
|
||||
header->id = 1;// MPEG Version: 0 for MPEG-4, 1 for MPEG-2
|
||||
header->layer = 0;// always 00
|
||||
header->protection_absent = 1;// 表示是否误码校验
|
||||
header->profile = 1;// 表示使用哪个级别的AAC, 有些芯片只支持AAC LC.
|
||||
header->sampling_frequency_index = 0xb;// 表示使用的采样率的下标
|
||||
header->private_bit = 0;
|
||||
header->channel_configuration = 1;// 表示声道数
|
||||
header->original_copy = 0;
|
||||
header->home = 0;
|
||||
}
|
||||
|
||||
void set_variable_header(adts_variable_header *header, const int aac_raw_data_length) {
|
||||
header->copyright_identification_bit = 0;
|
||||
header->copyright_identification_start = 0;
|
||||
header->aac_frame_length = aac_raw_data_length + 7;
|
||||
header->adts_buffer_fullness = 0x7f;
|
||||
header->number_of_raw_data_blocks_in_frame = 0;
|
||||
}
|
||||
|
||||
void get_fixed_header(const unsigned char buff[7], adts_fixed_header *header) {
|
||||
unsigned long long adts = 0;
|
||||
const unsigned char *p = buff;
|
||||
adts |= *p ++; adts <<= 8;
|
||||
adts |= *p ++; adts <<= 8;
|
||||
adts |= *p ++; adts <<= 8;
|
||||
adts |= *p ++; adts <<= 8;
|
||||
adts |= *p ++; adts <<= 8;
|
||||
adts |= *p ++; adts <<= 8;
|
||||
adts |= *p ++;
|
||||
|
||||
|
||||
header->syncword = (adts >> 44);
|
||||
header->id = (adts >> 43) & 0x01;
|
||||
header->layer = (adts >> 41) & 0x03;
|
||||
header->protection_absent = (adts >> 40) & 0x01;
|
||||
header->profile = (adts >> 38) & 0x03;
|
||||
header->sampling_frequency_index = (adts >> 34) & 0x0f;
|
||||
header->private_bit = (adts >> 33) & 0x01;
|
||||
header->channel_configuration = (adts >> 30) & 0x07;
|
||||
header->original_copy = (adts >> 29) & 0x01;
|
||||
header->home = (adts >> 28) & 0x01;
|
||||
}
|
||||
|
||||
void get_variable_header(const unsigned char buff[7], adts_variable_header *header) {
|
||||
unsigned long long adts = 0;
|
||||
adts = buff[0]; adts <<= 8;
|
||||
adts |= buff[1]; adts <<= 8;
|
||||
adts |= buff[2]; adts <<= 8;
|
||||
adts |= buff[3]; adts <<= 8;
|
||||
adts |= buff[4]; adts <<= 8;
|
||||
adts |= buff[5]; adts <<= 8;
|
||||
adts |= buff[6];
|
||||
|
||||
header->copyright_identification_bit = (adts >> 27) & 0x01;
|
||||
header->copyright_identification_start = (adts >> 26) & 0x01;
|
||||
header->aac_frame_length = (adts >> 13) & ((int)pow(2, 14) - 1);
|
||||
header->adts_buffer_fullness = (adts >> 2) & ((int)pow(2, 11) - 1);
|
||||
header->number_of_raw_data_blocks_in_frame = adts & 0x03;
|
||||
}
|
||||
|
||||
void convert_adts_header2int64(const adts_fixed_header *fixed_header, const adts_variable_header *variable_header, uint64_t *header) {
|
||||
uint64_t ret_value = 0;
|
||||
ret_value = ((fixed_header->syncword<<4) | 0x0F);
|
||||
ret_value <<= 1;
|
||||
ret_value |= fixed_header->id;
|
||||
ret_value <<= 2;
|
||||
ret_value |= fixed_header->layer;
|
||||
ret_value <<= 1;
|
||||
ret_value |= (fixed_header->protection_absent) & 0x01;
|
||||
ret_value <<= 2;
|
||||
ret_value |= fixed_header->profile;
|
||||
ret_value <<= 4;
|
||||
ret_value |= (fixed_header->sampling_frequency_index) & 0x0f;
|
||||
ret_value <<= 1;
|
||||
ret_value |= (fixed_header->private_bit) & 0x01;
|
||||
ret_value <<= 3;
|
||||
ret_value |= (fixed_header->channel_configuration) & 0x07;
|
||||
ret_value <<= 1;
|
||||
ret_value |= (fixed_header->original_copy) & 0x01;
|
||||
ret_value <<= 1;
|
||||
ret_value |= (fixed_header->home) & 0x01;
|
||||
|
||||
ret_value <<= 1;
|
||||
ret_value |= (variable_header->copyright_identification_bit) & 0x01;
|
||||
ret_value <<= 1;
|
||||
ret_value |= (variable_header->copyright_identification_start) & 0x01;
|
||||
ret_value <<= 13;
|
||||
ret_value |= (variable_header->aac_frame_length) & ((int)pow(2, 13) - 1);
|
||||
ret_value <<= 11;
|
||||
ret_value |= ((variable_header->adts_buffer_fullness<<4) | 0x0F ) & ((int)pow(2, 11) - 1);
|
||||
ret_value <<= 2;
|
||||
ret_value |= (variable_header->number_of_raw_data_blocks_in_frame) & ((int)pow(2, 2) - 1);
|
||||
|
||||
*header = ret_value;
|
||||
}
|
||||
|
||||
void convert_adts_header2char(const adts_fixed_header *fixed_header, const adts_variable_header *variable_header, unsigned char buffer[7]) {
|
||||
uint64_t value = 0;
|
||||
convert_adts_header2int64(fixed_header, variable_header, &value);
|
||||
buffer[0] = (value >> 48) & 0xff;
|
||||
buffer[1] = (value >> 40) & 0xff;
|
||||
buffer[2] = (value >> 32) & 0xff;
|
||||
buffer[3] = (value >> 24) & 0xff;
|
||||
buffer[4] = (value >> 16) & 0xff;
|
||||
buffer[5] = (value >> 8) & 0xff;
|
||||
buffer[6] = (value) & 0xff;
|
||||
}
|
||||
|
||||
void aac_dsi_to_adts(uint8_t *dsi, uint8_t *adts, uint32_t aac_data_length)
|
||||
{
|
||||
uint8_t audio_object_type = (dsi[0] >> 3) & 0x1F;
|
||||
uint8_t profile = audio_object_type - 1;
|
||||
uint8_t samplerate_index = ((dsi[0] & 0x07) << 1) | (dsi[1] >> 7);
|
||||
uint8_t channels = (dsi[1] >> 3) & 0x0F;
|
||||
;uint32_t frame_length = aac_data_length + 7;
|
||||
|
||||
adts[0] = 0xFF; //syncword hight 8 bits
|
||||
adts[1] = 0xF0; //syncword low 4 bits
|
||||
adts[1] |= (0x01 << 3); //ID 0:MPEG-4,1:MPEG-2
|
||||
adts[1] |= (0x00 << 1); //layer:00
|
||||
adts[1] |= (0x01 & 0x1); //1:no CRC,0:is CRC
|
||||
adts[2] = (profile << 6); //profile 0x01:AAC-LC
|
||||
adts[2] |= (samplerate_index << 2);
|
||||
adts[2] |= (0x00 << 1); //private_bit (0)
|
||||
adts[2] |= (channels & 0x4) >> 2;
|
||||
adts[3] = (channels & 0x3) << 6;
|
||||
adts[3] |= (frame_length >> 11); //frame_length bits12-bits13
|
||||
adts[4] = (frame_length >> 3) & 0xFF; //frame_length bits4-bits11
|
||||
adts[5] = (frame_length & 0x07) << 5; //frame_length low 3 bits first
|
||||
adts[5] |= (0x7FF >> 6) & 0x1F; //adts_buffer_fullness high 5 bits
|
||||
adts[6] = (0x7FF & 0x3F) << 2; //adts_buffer_fullness low 6 bits
|
||||
adts[6] |= (0x00); //number_of_raw_data_blocks_in_frame (0)
|
||||
}
|
||||
67
sdk/lib/video/miniMP4/adts.h
Normal file
67
sdk/lib/video/miniMP4/adts.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @file adts.h
|
||||
* @brief
|
||||
* @author licaibiao
|
||||
* @version 1.0
|
||||
* @date 2023-12-06
|
||||
*
|
||||
* @copyright Copyright (c) 2023-2030 liwen01 Technology Co., Ltd
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AdtsHeader__adts__
|
||||
#define __AdtsHeader__adts__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* ADTS 全称: Audio Data Transport Stream. 是 AAC音频的传输流格式.
|
||||
* ADTS头中相对有用的信息包括: 采样率, 声道数, 帧长度. 每一个带ADTS头信息的AAC流都会清晰的告诉解码器他需要的这些信息.
|
||||
* 一般情况下ADTS的头信息都是7个字节, 分为两部分: 前28bit是 adts_fixed_header, 后28bit是 adts_variable_header.
|
||||
*/
|
||||
|
||||
typedef struct adts_fixed_header {
|
||||
unsigned short syncword: 12;
|
||||
unsigned char id: 1;
|
||||
unsigned char layer: 2;
|
||||
unsigned char protection_absent: 1;
|
||||
unsigned char profile: 2;
|
||||
unsigned char sampling_frequency_index: 4;
|
||||
unsigned char private_bit: 1;
|
||||
unsigned char channel_configuration: 3;
|
||||
unsigned char original_copy: 1;
|
||||
unsigned char home: 1;
|
||||
} adts_fixed_header; // length : 28 bits
|
||||
|
||||
typedef struct adts_variable_header {
|
||||
unsigned char copyright_identification_bit: 1;
|
||||
unsigned char copyright_identification_start: 1;
|
||||
unsigned short aac_frame_length: 13;
|
||||
unsigned short adts_buffer_fullness: 11;
|
||||
unsigned char number_of_raw_data_blocks_in_frame:2;
|
||||
} adts_variable_header; // length : 28 bits
|
||||
|
||||
// 设置adts固定的一部分
|
||||
extern void set_fixed_header(adts_fixed_header *header);
|
||||
|
||||
// 设置adts可变的一部分
|
||||
extern void set_variable_header(adts_variable_header *header, const int aac_raw_data_length);
|
||||
|
||||
|
||||
// 解析buff中的adts固定部分头信息
|
||||
extern void get_fixed_header(const unsigned char buff[7], adts_fixed_header *header);
|
||||
|
||||
// 解析buff中的adts可变部分头信息
|
||||
extern void get_variable_header(const unsigned char buff[7], adts_variable_header *header);
|
||||
|
||||
|
||||
// 将adts头信息转化为一个64位的整数, PS: 前面8位空着
|
||||
extern void convert_adts_header2int64(const adts_fixed_header *fixed_header, const adts_variable_header *variable_header, uint64_t *header);
|
||||
|
||||
// 将adts头信息转化为一个7字节的buff
|
||||
extern void convert_adts_header2char(const adts_fixed_header *fixed_header, const adts_variable_header *variable_header, unsigned char buffer[7]);
|
||||
|
||||
extern void aac_dsi_to_adts(uint8_t *dsi, uint8_t *adts, uint32_t aac_data_length);
|
||||
|
||||
#endif /* defined(__AdtsHeader__adts__) */
|
||||
1717
sdk/lib/video/miniMP4/mp4_demux_msi.c
Normal file
1717
sdk/lib/video/miniMP4/mp4_demux_msi.c
Normal file
File diff suppressed because it is too large
Load Diff
1340
sdk/lib/video/miniMP4/mp4_encode_msi2.c
Normal file
1340
sdk/lib/video/miniMP4/mp4_encode_msi2.c
Normal file
File diff suppressed because it is too large
Load Diff
438
sdk/lib/video/miniMP4/time_lapse_mp4.c
Normal file
438
sdk/lib/video/miniMP4/time_lapse_mp4.c
Normal file
@@ -0,0 +1,438 @@
|
||||
|
||||
/**********************************************************************
|
||||
* 缩时录影的基本代码demo
|
||||
*********************************************************************/
|
||||
#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 "mp4/mp4_encode.h"
|
||||
// 结构体申请空间函数
|
||||
#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
|
||||
|
||||
enum
|
||||
{
|
||||
MSI_MP4_STOP = BIT(0),
|
||||
MSI_MP4_THREAD_DEAD = BIT(1),
|
||||
};
|
||||
|
||||
#define TIME_LAPSE_DIR "0:/DCIM"
|
||||
#define MP4_FILE_NAME "mp4"
|
||||
|
||||
struct mp4_encode_msi_s
|
||||
{
|
||||
struct msi *msi;
|
||||
struct os_event evt;
|
||||
uint16_t rec_time;
|
||||
uint16_t filter_type;
|
||||
};
|
||||
|
||||
#define MIN(a, b) ((a) > (b) ? b : a)
|
||||
#define MAX(a, b) ((a) > (b) ? a : b)
|
||||
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 *creat_mp4_file(char *dir_name)
|
||||
{
|
||||
|
||||
void *fp;
|
||||
char filepath[64];
|
||||
uint32_t indx = os_jiffies() % 99999999;
|
||||
void *dir = osal_opendir(dir_name);
|
||||
if (!dir)
|
||||
{
|
||||
osal_fmkdir(dir_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_closedir(dir);
|
||||
}
|
||||
|
||||
sprintf(filepath, "%s/%08d.%s", dir_name, indx, MP4_FILE_NAME);
|
||||
printf("filepath:%s\r\n", filepath);
|
||||
fp = osal_fopen(filepath, "wb+");
|
||||
return fp;
|
||||
}
|
||||
|
||||
static void *creat_mp4_file2(char *dir_name, char *filename)
|
||||
{
|
||||
|
||||
void *fp;
|
||||
char filepath[64];
|
||||
uint32_t indx = os_jiffies();
|
||||
void *dir = osal_opendir(dir_name);
|
||||
if (!dir)
|
||||
{
|
||||
osal_fmkdir(dir_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
osal_closedir(dir);
|
||||
}
|
||||
sprintf(filename, "%016d.jpg", indx);
|
||||
sprintf(filepath, "%s/%016d.%s", dir_name, indx, MP4_FILE_NAME);
|
||||
printf("filepath:%s\r\n", filepath);
|
||||
fp = osal_fopen(filepath, "wb+");
|
||||
return fp;
|
||||
}
|
||||
|
||||
// 获取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)
|
||||
{
|
||||
int ret = 1;
|
||||
struct mp4_encode_msi_s *mp4_encode = (struct mp4_encode_msi_s *) msi->priv;
|
||||
//struct msi *mp4_thumb_msi = NULL;
|
||||
void *mp4_msg = NULL;
|
||||
void *fp = NULL;
|
||||
struct framebuff *fb = NULL;
|
||||
int error = 0;
|
||||
uint8_t nal_head_size;
|
||||
uint32_t nal_size;
|
||||
char h264_filename[64];
|
||||
|
||||
uint8_t *buf;
|
||||
uint8_t *nal_head_buf;
|
||||
uint8_t *last_nal_head_buf;
|
||||
|
||||
int write_size = 0;
|
||||
uint32_t MP4_status = 0;
|
||||
uint32_t write_start_time = os_jiffies();
|
||||
//uint8_t sps_pps_flag = 0;
|
||||
uint8_t last_num = 0;
|
||||
(void) last_num;
|
||||
uint32_t v_count = 0;
|
||||
//uint32_t audio_save_time = 0;
|
||||
// 参考minimp4的值去配置
|
||||
//uint8_t asps_data[2] = {0x15, 0x88};
|
||||
|
||||
fp = creat_mp4_file2(TIME_LAPSE_DIR, h264_filename);
|
||||
if (!fp)
|
||||
{
|
||||
os_sleep_ms(1);
|
||||
goto mp4_encode_thread_end;
|
||||
}
|
||||
|
||||
mp4_msg = MP4_open_init(fp, 0);
|
||||
if (!mp4_msg)
|
||||
{
|
||||
goto mp4_encode_thread_end;
|
||||
}
|
||||
mp4_video_cfg_init(mp4_msg, 1280, 720);
|
||||
ret = 0;
|
||||
os_printf(KERN_INFO "%s:%d\n", __FUNCTION__, __LINE__);
|
||||
while (fp)
|
||||
{
|
||||
//mp4_encode_running_again:
|
||||
os_event_wait(&mp4_encode->evt, MSI_MP4_STOP, &MP4_status, OS_EVENT_WMODE_OR, 0);
|
||||
// 结束写卡
|
||||
if (MP4_status & MSI_MP4_STOP)
|
||||
{
|
||||
ret = 1;
|
||||
goto mp4_encode_thread_end;
|
||||
}
|
||||
fb = msi_get_fb(msi, 0);
|
||||
if (fb && (fb->mtype == F_H264))
|
||||
{
|
||||
buf = fb->data;
|
||||
nal_head_size = 0;
|
||||
nal_head_buf = buf;
|
||||
// 记录最后一次nal的头位置,如果没有pps或者sps,这个就是I帧或者P帧
|
||||
last_nal_head_buf = nal_head_buf;
|
||||
mp4_encode_thread_again:
|
||||
|
||||
// 检查对应头部是否是nal
|
||||
// nal_head_size = get_nal_size(buf + buf_offset, 64, 0,&cur_offset);
|
||||
// 检查是否存在pps或者sps,只是检查64byte就好了,硬件产生
|
||||
nal_head_buf = get_sps_pps_nal_size(nal_head_buf, 64, &nal_size, &nal_head_size);
|
||||
|
||||
// 找到pps或者sps
|
||||
if (nal_head_buf)
|
||||
{
|
||||
error |= write_h264_pps_sps(mp4_msg, nal_head_buf, nal_size + nal_head_size);
|
||||
if (0 != error)
|
||||
{
|
||||
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
|
||||
goto mp4_encode_thread_end;
|
||||
}
|
||||
|
||||
// 查看下一个nal是否为pps或者sps
|
||||
nal_head_buf += (nal_size + nal_head_size);
|
||||
last_nal_head_buf = nal_head_buf;
|
||||
|
||||
goto mp4_encode_thread_again;
|
||||
}
|
||||
|
||||
// 写剩余的nal数据
|
||||
_os_printf(KERN_INFO "T");
|
||||
v_count++;
|
||||
error |= write_h264_data(mp4_msg, last_nal_head_buf, fb->len - (last_nal_head_buf - fb->data), 120);
|
||||
if (0 != error)
|
||||
{
|
||||
goto mp4_encode_thread_end;
|
||||
}
|
||||
|
||||
write_size += (fb->len - (last_nal_head_buf - fb->data));
|
||||
msi_delete_fb(NULL, fb);
|
||||
fb = NULL;
|
||||
if (os_jiffies() - write_start_time >= save_time)
|
||||
{
|
||||
goto mp4_encode_thread_end;
|
||||
}
|
||||
|
||||
// 同步,缩时录影直接同步,不需要考虑定时,因为本身就是很久才录制一次
|
||||
error |= mp4_syn(mp4_msg);
|
||||
if (0 != error)
|
||||
{
|
||||
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
|
||||
goto mp4_encode_thread_end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msi_delete_fb(NULL, fb);
|
||||
fb = NULL;
|
||||
}
|
||||
os_sleep_ms(1);
|
||||
}
|
||||
|
||||
mp4_encode_thread_end:
|
||||
if (fb)
|
||||
{
|
||||
msi_delete_fb(NULL, fb);
|
||||
}
|
||||
|
||||
if (mp4_msg)
|
||||
{
|
||||
mp4_deinit(mp4_msg);
|
||||
}
|
||||
|
||||
if (fp)
|
||||
{
|
||||
osal_fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
// 如果遇到写入错误之类,直接删除缓冲区的吧,防止写卡慢导致后面的帧不是连续的
|
||||
if (error)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
fb = msi_get_fb(msi, 0);
|
||||
if (fb)
|
||||
{
|
||||
msi_delete_fb(NULL, fb);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
os_printf("mp4 encode end\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 测试文件保存,保存一分钟吧,一直录卡,直到关闭msi
|
||||
static void mp4_encode_thread(void *d)
|
||||
{
|
||||
struct msi *msi = (struct msi *) d;
|
||||
struct mp4_encode_msi_s *mp4_encode = (struct mp4_encode_msi_s *) msi->priv;
|
||||
int ret = 0;
|
||||
//int res;
|
||||
msi_get(msi);
|
||||
while (msi)
|
||||
{
|
||||
msi->enable = 1;
|
||||
ret = mp4_encode_running(msi, 60 * 1000 * mp4_encode->rec_time);
|
||||
msi->enable = 0;
|
||||
os_printf("%s:%d end\n", __FUNCTION__, __LINE__);
|
||||
if (ret)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
//mp4_encode_thread_end:
|
||||
|
||||
os_event_set(&mp4_encode->evt, MSI_MP4_THREAD_DEAD, NULL);
|
||||
msi_put(msi);
|
||||
os_printf("%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);
|
||||
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_H264 && mp4_encode->filter_type != (uint16_t) ~0)
|
||||
{
|
||||
ret = RET_ERR;
|
||||
if (mp4_encode->filter_type == fb->stype)
|
||||
{
|
||||
struct fb_h264_s *h264_s = (struct fb_h264_s *) fb->priv;
|
||||
// 只是支持I帧
|
||||
if (h264_s->type == 1)
|
||||
{
|
||||
// os_printf(KERN_INFO"recv I frame\n");
|
||||
ret = RET_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct msi *time_lapse_mp4_encode_msi2_init(const char *mp4_msi_name, uint16_t filter_type, uint16_t rec_time)
|
||||
{
|
||||
struct mp4_encode_msi_s *mp4_encode = NULL;
|
||||
struct msi *msi = msi_new(mp4_msi_name, 64, NULL);
|
||||
if (msi && !msi->priv)
|
||||
{
|
||||
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->rec_time = rec_time;
|
||||
msi->priv = mp4_encode;
|
||||
os_event_init(&mp4_encode->evt);
|
||||
mp4_encode->msi = msi;
|
||||
msi->action = MP4_encode_msi_action;
|
||||
msi->enable = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 不要重复打开,同一个名称需要等待上一次写入完成后并且关闭后才可以重新打开
|
||||
// 因为这里new了一次,所以要destroy一次(new和destroy要配对,实际msi的destroy是在另一个地方)
|
||||
if (msi)
|
||||
{
|
||||
msi_destroy(msi);
|
||||
msi = NULL;
|
||||
goto mp4_encode_msi_init_end;
|
||||
}
|
||||
}
|
||||
|
||||
void *mp4_hdl = os_task_create("time_lapse_mp4", mp4_encode_thread, msi, OS_TASK_PRIORITY_NORMAL, 0, NULL, 2048);
|
||||
os_printf("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;
|
||||
}
|
||||
Reference in New Issue
Block a user