622 lines
17 KiB
C
622 lines
17 KiB
C
|
|
#include "avimuxer.h"
|
||
|
|
#include "basic_include.h"
|
||
|
|
#include "fatfs/osal_file.h"
|
||
|
|
#include "lib/heap/av_heap.h"
|
||
|
|
#include "lib/heap/av_psram_heap.h"
|
||
|
|
#include "stream_define.h"
|
||
|
|
|
||
|
|
const uint8_t avi_zero = 0;
|
||
|
|
#define CONTENT_MAX_SIZE (512 * 1024 * 1024)
|
||
|
|
|
||
|
|
#ifndef SEEK_SET
|
||
|
|
#define SEEK_SET 0 /* set file offset to offset */
|
||
|
|
#endif
|
||
|
|
#ifndef SEEK_CUR
|
||
|
|
#define SEEK_CUR 1 /* set file offset to current plus offset */
|
||
|
|
#endif
|
||
|
|
#ifndef SEEK_END
|
||
|
|
#define SEEK_END 2 /* set file offset to EOF plus offset */
|
||
|
|
#endif
|
||
|
|
|
||
|
|
|
||
|
|
static uint32_t avi_tell(F_FILE *fp)
|
||
|
|
{
|
||
|
|
return osal_ftell(fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void pre_avi_seek(F_FILE *fp, uint32_t offset)
|
||
|
|
{
|
||
|
|
uint32_t filesize = osal_fsize(fp);
|
||
|
|
if(filesize != offset)
|
||
|
|
{
|
||
|
|
osal_fseek(fp, offset);
|
||
|
|
osal_ftruncate(fp);
|
||
|
|
_os_printf("avi size: %d\n", osal_fsize(fp));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t avi_seek(F_FILE *fp, int32_t offset, int seek_mode)
|
||
|
|
{
|
||
|
|
uint32_t fp_offset = 0;
|
||
|
|
uint32_t filesize = osal_fsize(fp);
|
||
|
|
if (seek_mode == SEEK_SET)
|
||
|
|
{
|
||
|
|
fp_offset = offset;
|
||
|
|
}
|
||
|
|
else if (seek_mode == SEEK_CUR)
|
||
|
|
{
|
||
|
|
fp_offset = osal_ftell(fp) + offset;
|
||
|
|
}
|
||
|
|
else if (seek_mode == SEEK_END)
|
||
|
|
{
|
||
|
|
fp_offset = osal_fsize(fp) + offset;
|
||
|
|
}
|
||
|
|
osal_fseek(fp, fp_offset);
|
||
|
|
if (filesize < fp_offset)
|
||
|
|
{
|
||
|
|
osal_ftruncate(fp);
|
||
|
|
}
|
||
|
|
return offset;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t avi_write(void *buf, uint32_t size, uint32_t n, F_FILE *fp)
|
||
|
|
{
|
||
|
|
// 返回值0是代表异常
|
||
|
|
uint32_t ret = 1;
|
||
|
|
uint32_t write_size_total = size * n;
|
||
|
|
ret = osal_fwrite(buf, 1, write_size_total, fp);
|
||
|
|
return !ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static F_FILE *avi_open(const char *filename, char *mode)
|
||
|
|
{
|
||
|
|
return osal_fopen(filename, mode);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void avi_close(F_FILE *fp)
|
||
|
|
{
|
||
|
|
osal_fclose(fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void avi_truncate(F_FILE *fp, uint32_t offset)
|
||
|
|
{
|
||
|
|
avi_seek(fp, offset, SEEK_CUR); // 预留的的空间
|
||
|
|
osal_ftruncate(fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
static void avi_file_syn(F_FILE *fp)
|
||
|
|
{
|
||
|
|
osal_fsync(fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// 结构体申请空间函数
|
||
|
|
#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 AVIF_HASINDEX (1 << 4)
|
||
|
|
#define AVIF_ISINTERLEAVED (1 << 8)
|
||
|
|
#define AVIIF_KEYFRAME (1 << 4)
|
||
|
|
|
||
|
|
#define AVI_AUDIO_FRAME (0 << 31)
|
||
|
|
#define AVI_VIDEO_FRAME (1 << 31)
|
||
|
|
#define AVI_KEY_FRAME (1 << 30)
|
||
|
|
#define AVI_INSERT_FRAME (1 << 29)
|
||
|
|
|
||
|
|
#ifndef offsetof
|
||
|
|
#define offsetof(type, member) ((size_t) &((type *) 0)->member)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define AVI_LIST_EMP (512)
|
||
|
|
#define IDX_MAX_SIZE (1024*1024)
|
||
|
|
|
||
|
|
#pragma pack(1)
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
uint32_t microsec_per_frame;
|
||
|
|
uint32_t maxbytes_per_Sec;
|
||
|
|
uint32_t padding_granularity;
|
||
|
|
uint32_t flags;
|
||
|
|
uint32_t total_frames;
|
||
|
|
uint32_t initial_frames;
|
||
|
|
uint32_t number_streams;
|
||
|
|
uint32_t suggested_bufsize;
|
||
|
|
uint32_t width;
|
||
|
|
uint32_t height;
|
||
|
|
uint32_t reserved[4];
|
||
|
|
} AVI_HEADER;
|
||
|
|
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
char fcc_type[4];
|
||
|
|
char fcc_codec[4];
|
||
|
|
uint32_t flags;
|
||
|
|
uint16_t priority;
|
||
|
|
uint16_t language;
|
||
|
|
uint32_t initial_frames;
|
||
|
|
uint32_t scale;
|
||
|
|
uint32_t rate;
|
||
|
|
uint32_t start;
|
||
|
|
uint32_t length;
|
||
|
|
uint32_t suggested_bufsize;
|
||
|
|
uint32_t quality;
|
||
|
|
uint32_t sample_size;
|
||
|
|
uint16_t vrect_left;
|
||
|
|
uint16_t vrect_top;
|
||
|
|
uint16_t vrect_right;
|
||
|
|
uint16_t vrect_bottom;
|
||
|
|
|
||
|
|
} STREAM_HEADER;
|
||
|
|
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
uint16_t format_tag;
|
||
|
|
uint16_t channels;
|
||
|
|
uint32_t sample_per_sec;
|
||
|
|
uint32_t avgbyte_per_sec;
|
||
|
|
uint16_t block_align;
|
||
|
|
uint16_t bits_per_sample;
|
||
|
|
uint16_t size;
|
||
|
|
} WAVE_FORMAT;
|
||
|
|
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
uint32_t size;
|
||
|
|
uint32_t width;
|
||
|
|
uint32_t height;
|
||
|
|
uint16_t planes;
|
||
|
|
uint16_t bitcount;
|
||
|
|
uint32_t compression;
|
||
|
|
uint32_t image_size;
|
||
|
|
uint32_t xpels_per_meter;
|
||
|
|
uint32_t ypels_per_meter;
|
||
|
|
uint32_t color_used;
|
||
|
|
uint32_t color_important;
|
||
|
|
} BITMAP_FORMAT;
|
||
|
|
|
||
|
|
typedef struct
|
||
|
|
{
|
||
|
|
uint32_t *framesize_lst;
|
||
|
|
uint32_t framesize_fix;
|
||
|
|
uint32_t framesize_idx;
|
||
|
|
uint32_t framesize_max;
|
||
|
|
uint32_t movi_addr;
|
||
|
|
uint32_t movi_addr_end;
|
||
|
|
uint32_t cur_addr;
|
||
|
|
uint32_t frame_base_addr;
|
||
|
|
uint32_t max_size;
|
||
|
|
uint32_t curpos;
|
||
|
|
|
||
|
|
uint32_t now_idx;
|
||
|
|
uint32_t cache_idx;
|
||
|
|
uint32_t total_idx;
|
||
|
|
uint32_t frame_list[AVI_LIST_EMP / 4];
|
||
|
|
|
||
|
|
uint32_t tmp_idx_offset;
|
||
|
|
uint8_t tmp_idx_data[AVI_LIST_EMP / 4 * 16];
|
||
|
|
F_FILE *fp;
|
||
|
|
uint32_t extern_fp;
|
||
|
|
|
||
|
|
char riff[4];
|
||
|
|
uint32_t riff_size;
|
||
|
|
char type_avi[4];
|
||
|
|
|
||
|
|
char hlist[4];
|
||
|
|
uint32_t hlist_size;
|
||
|
|
char type_hdrl[4];
|
||
|
|
|
||
|
|
char avih[4];
|
||
|
|
uint32_t avih_size;
|
||
|
|
AVI_HEADER avi_header;
|
||
|
|
#if 1
|
||
|
|
char slist1[4];
|
||
|
|
uint32_t slist1_size;
|
||
|
|
char type_str1[4];
|
||
|
|
|
||
|
|
char strhdr1[4];
|
||
|
|
uint32_t strhdr1_size;
|
||
|
|
STREAM_HEADER strhdr_audio;
|
||
|
|
|
||
|
|
char strfmt1[4];
|
||
|
|
uint32_t strfmt1_size;
|
||
|
|
WAVE_FORMAT strfmt_audio;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
char slist2[4];
|
||
|
|
uint32_t slist2_size;
|
||
|
|
char type_str2[4];
|
||
|
|
|
||
|
|
char strhdr2[4];
|
||
|
|
uint32_t strhdr2_size;
|
||
|
|
STREAM_HEADER strhdr_video;
|
||
|
|
|
||
|
|
char strfmt2[4];
|
||
|
|
uint32_t strfmt2_size;
|
||
|
|
BITMAP_FORMAT strfmt_video;
|
||
|
|
|
||
|
|
char mlist[4];
|
||
|
|
uint32_t mlist_size;
|
||
|
|
char type_movi[4];
|
||
|
|
|
||
|
|
} AVI_FILE;
|
||
|
|
#pragma pack()
|
||
|
|
|
||
|
|
static uint32_t avi_write_idx_tmp(void *buf, uint32_t size, uint32_t n, AVI_FILE *avi)
|
||
|
|
{
|
||
|
|
// 返回值0是代表异常
|
||
|
|
uint32_t ret = 0;
|
||
|
|
uint32_t write_size_total = size * n;
|
||
|
|
os_memcpy(avi->tmp_idx_data + avi->tmp_idx_offset, buf, write_size_total);
|
||
|
|
avi->tmp_idx_offset += write_size_total;
|
||
|
|
return !ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static uint32_t avi_write_idx_syn(AVI_FILE *avi)
|
||
|
|
{
|
||
|
|
// 返回值0是代表异常
|
||
|
|
uint32_t ret = avi_write(avi->tmp_idx_data, 1, avi->tmp_idx_offset, avi->fp);
|
||
|
|
avi->tmp_idx_offset = 0;
|
||
|
|
return !ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
void *avimuxer_init2(void *fp, uint32_t max_size, int w, int h, int frate, int gop, int h265, int sampnum)
|
||
|
|
{
|
||
|
|
int samprate = 8000, channels = 1, sampbits = 16;
|
||
|
|
AVI_FILE *avi = STREAM_ZALLOC(1 * sizeof(AVI_FILE));
|
||
|
|
if (!avi)
|
||
|
|
{
|
||
|
|
goto failed;
|
||
|
|
}
|
||
|
|
avi->extern_fp = 1;
|
||
|
|
avi->fp = (F_FILE *) fp;
|
||
|
|
if (!avi->fp)
|
||
|
|
{
|
||
|
|
goto failed;
|
||
|
|
}
|
||
|
|
|
||
|
|
//预先分配空间
|
||
|
|
pre_avi_seek(avi->fp, max_size);
|
||
|
|
|
||
|
|
//开始写入数据头
|
||
|
|
avi_seek(avi->fp, 0, SEEK_SET);
|
||
|
|
|
||
|
|
|
||
|
|
memcpy(avi->avih, "avih", 4);
|
||
|
|
avi->avih_size = sizeof(AVI_HEADER);
|
||
|
|
avi->avi_header.microsec_per_frame = 1000000 / frate;
|
||
|
|
avi->avi_header.maxbytes_per_Sec = w * h * 3;
|
||
|
|
avi->avi_header.flags = AVIF_ISINTERLEAVED | AVIF_HASINDEX;
|
||
|
|
avi->avi_header.number_streams = 1;
|
||
|
|
avi->avi_header.width = w;
|
||
|
|
avi->avi_header.height = h;
|
||
|
|
avi->avi_header.suggested_bufsize = w * h * 3;
|
||
|
|
#if 1
|
||
|
|
memcpy(avi->strhdr1, "strh", 4);
|
||
|
|
memcpy(avi->strhdr_audio.fcc_type, "auds", 4);
|
||
|
|
memcpy(avi->strhdr_audio.fcc_codec, "PCM ", 4);
|
||
|
|
avi->strhdr1_size = sizeof(STREAM_HEADER);
|
||
|
|
avi->strhdr_audio.scale = 1;
|
||
|
|
avi->strhdr_audio.rate = samprate;
|
||
|
|
avi->strhdr_audio.suggested_bufsize = samprate * channels * sampbits / 8;
|
||
|
|
avi->strhdr_audio.sample_size = channels * sampbits / 8;
|
||
|
|
|
||
|
|
memcpy(avi->strfmt1, "strf", 4);
|
||
|
|
avi->strfmt1_size = sizeof(WAVE_FORMAT);
|
||
|
|
avi->strfmt_audio.format_tag = 1;
|
||
|
|
avi->strfmt_audio.channels = channels;
|
||
|
|
avi->strfmt_audio.sample_per_sec = samprate;
|
||
|
|
avi->strfmt_audio.avgbyte_per_sec = samprate * channels * sampbits / 8;
|
||
|
|
avi->strfmt_audio.block_align = channels * sampbits / 8;
|
||
|
|
avi->strfmt_audio.bits_per_sample = sampbits;
|
||
|
|
|
||
|
|
memcpy(avi->slist1, "LIST", 4);
|
||
|
|
memcpy(avi->type_str1, "strl", 4);
|
||
|
|
avi->slist1_size = offsetof(AVI_FILE, slist2) - offsetof(AVI_FILE, type_str1);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
memcpy(avi->strhdr2, "strh", 4);
|
||
|
|
memcpy(avi->strhdr_video.fcc_type, "vids", 4);
|
||
|
|
memcpy(avi->strhdr_video.fcc_codec, h265 ? "MJPG" : "MJPG", 4);
|
||
|
|
avi->strhdr2_size = sizeof(STREAM_HEADER);
|
||
|
|
avi->strhdr_video.scale = 1;
|
||
|
|
avi->strhdr_video.rate = frate;
|
||
|
|
avi->strhdr_video.suggested_bufsize = 0;
|
||
|
|
avi->strhdr_video.quality = -1;
|
||
|
|
avi->strhdr_video.vrect_right = w;
|
||
|
|
avi->strhdr_video.vrect_bottom = h;
|
||
|
|
|
||
|
|
memcpy(avi->strfmt2, "strf", 4);
|
||
|
|
avi->strfmt2_size = sizeof(BITMAP_FORMAT);
|
||
|
|
avi->strfmt_video.size = 40;
|
||
|
|
avi->strfmt_video.width = w;
|
||
|
|
avi->strfmt_video.height = h;
|
||
|
|
avi->strfmt_video.planes = 1;
|
||
|
|
avi->strfmt_video.bitcount = 24;
|
||
|
|
avi->strfmt_video.compression = h265 ? (('H' << 0) | ('E' << 8) | ('V' << 16) | ('1' << 24)) : (('M' << 0) | ('J' << 8) | ('P' << 16) | ('G' << 24));
|
||
|
|
avi->strfmt_video.image_size = w * h * 3;
|
||
|
|
|
||
|
|
memcpy(avi->slist2, "LIST", 4);
|
||
|
|
memcpy(avi->type_str2, "strl", 4);
|
||
|
|
avi->slist2_size = 4 + 4 + 4 + avi->strhdr2_size + 4 + 4 + avi->strfmt2_size;
|
||
|
|
|
||
|
|
memcpy(avi->riff, "RIFF", 4);
|
||
|
|
memcpy(avi->type_avi, "AVI ", 4);
|
||
|
|
memcpy(avi->hlist, "LIST", 4);
|
||
|
|
memcpy(avi->type_hdrl, "hdrl", 4);
|
||
|
|
memcpy(avi->mlist, "LIST", 4);
|
||
|
|
memcpy(avi->type_movi, "movi", 4);
|
||
|
|
avi->hlist_size = sizeof(AVI_FILE) - 12 - offsetof(AVI_FILE, type_hdrl);
|
||
|
|
|
||
|
|
avi_write(&avi->riff, sizeof(AVI_FILE) - offsetof(AVI_FILE, riff), 1, avi->fp);
|
||
|
|
|
||
|
|
// 预分配文件空间
|
||
|
|
uint32_t movi_addr = avi_tell(avi->fp);
|
||
|
|
avi->movi_addr = movi_addr;
|
||
|
|
|
||
|
|
avi->max_size = max_size - movi_addr - 8 - IDX_MAX_SIZE;
|
||
|
|
|
||
|
|
avi->movi_addr_end = movi_addr + avi->max_size;
|
||
|
|
avi->frame_base_addr = avi->movi_addr_end;
|
||
|
|
avi->cur_addr = movi_addr;
|
||
|
|
return avi;
|
||
|
|
|
||
|
|
failed:
|
||
|
|
if (avi)
|
||
|
|
{
|
||
|
|
STREAM_FREE(avi);
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void avimuxer_fix_data2(AVI_FILE *avi, int writeidx)
|
||
|
|
{
|
||
|
|
// 只有缓冲区的时候才需要回写
|
||
|
|
if (avi->cache_idx)
|
||
|
|
{
|
||
|
|
uint32_t data, movisize;
|
||
|
|
avi->avi_header.total_frames = avi->strhdr_video.length;
|
||
|
|
|
||
|
|
data = avi->avi_header.total_frames;
|
||
|
|
avi_seek(avi->fp, offsetof(AVI_FILE, avi_header.total_frames) - offsetof(AVI_FILE, riff), SEEK_SET);
|
||
|
|
avi_write(&data, 4, 1, avi->fp);
|
||
|
|
|
||
|
|
#if 1
|
||
|
|
data = avi->strhdr_audio.length;
|
||
|
|
avi_seek(avi->fp, offsetof(AVI_FILE, strhdr_audio.length) - offsetof(AVI_FILE, riff), SEEK_SET);
|
||
|
|
avi_write(&data, 4, 1, avi->fp);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
data = avi->strhdr_video.length;
|
||
|
|
avi_seek(avi->fp, offsetof(AVI_FILE, strhdr_video.length) - offsetof(AVI_FILE, riff), SEEK_SET);
|
||
|
|
avi_write(&data, 4, 1, avi->fp);
|
||
|
|
|
||
|
|
movisize = avi->max_size + 4;
|
||
|
|
avi_seek(avi->fp, offsetof(AVI_FILE, mlist_size) - offsetof(AVI_FILE, riff), SEEK_SET);
|
||
|
|
avi_write(&movisize, 4, 1, avi->fp);
|
||
|
|
|
||
|
|
data = avi->max_size + sizeof(AVI_FILE) - offsetof(AVI_FILE, riff) + avi->total_idx * 16;
|
||
|
|
avi_seek(avi->fp, offsetof(AVI_FILE, riff_size) - offsetof(AVI_FILE, riff), SEEK_SET);
|
||
|
|
avi_write(&data, 4, 1, avi->fp);
|
||
|
|
|
||
|
|
if (writeidx)
|
||
|
|
{
|
||
|
|
|
||
|
|
// 如果相等,需要写入idx1的头
|
||
|
|
avi_seek(avi->fp, avi->frame_base_addr, SEEK_SET);
|
||
|
|
if (avi->movi_addr_end == avi_tell(avi->fp))
|
||
|
|
{
|
||
|
|
uint32_t idx1size;
|
||
|
|
avi_write("idx1", 4, 1, avi->fp);
|
||
|
|
idx1size = avi->total_idx * sizeof(uint32_t) * 4;
|
||
|
|
avi_write(&idx1size, 4, 1, avi->fp);
|
||
|
|
avi->curpos = 4;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
uint32_t idx1size;
|
||
|
|
uint32_t seek_tmp = avi_tell(avi->fp);
|
||
|
|
idx1size = avi->total_idx * sizeof(uint32_t) * 4;
|
||
|
|
avi_seek(avi->fp, avi->movi_addr_end+4, SEEK_SET);
|
||
|
|
avi_write(&idx1size, 4, 1, avi->fp);
|
||
|
|
avi_seek(avi->fp, seek_tmp, SEEK_SET);
|
||
|
|
}
|
||
|
|
while (avi->now_idx < avi->cache_idx)
|
||
|
|
{
|
||
|
|
avi_write_idx_tmp((avi->frame_list[avi->now_idx] & AVI_VIDEO_FRAME) ? "01dc" : "00wb", 4, 1, avi);
|
||
|
|
data = (avi->frame_list[avi->now_idx] & AVI_KEY_FRAME) ? AVIIF_KEYFRAME : 0;
|
||
|
|
avi_write_idx_tmp(&data, 4, 1, avi);
|
||
|
|
data = avi->curpos;
|
||
|
|
avi_write_idx_tmp(&data, 4, 1, avi);
|
||
|
|
data = avi->frame_list ? avi->frame_list[avi->now_idx] & 0x0fffffff : 0;
|
||
|
|
avi_write_idx_tmp(&data, 4, 1, avi);
|
||
|
|
// 如果是补帧,则不需要增加偏移?
|
||
|
|
if (avi->frame_list[avi->now_idx] & AVI_INSERT_FRAME)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
avi->curpos += data + 8;
|
||
|
|
}
|
||
|
|
|
||
|
|
avi->now_idx++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 一次性写入索引
|
||
|
|
avi_write_idx_syn(avi);
|
||
|
|
// 记录当前的位置
|
||
|
|
avi->frame_base_addr = avi_tell(avi->fp);
|
||
|
|
|
||
|
|
//如果有空闲,需要添加junk
|
||
|
|
if(osal_fsize(avi->fp) > avi->frame_base_addr+8)
|
||
|
|
{
|
||
|
|
uint32_t remain = osal_fsize(avi->fp) - avi->frame_base_addr - 8;
|
||
|
|
avi_write("JUNK", 4, 1, avi->fp);
|
||
|
|
avi_write(&remain, 4, 1, avi->fp);
|
||
|
|
}
|
||
|
|
else if(osal_fsize(avi->fp) > avi->frame_base_addr)
|
||
|
|
{
|
||
|
|
avi_write("JUNK", 4, 1, avi->fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
avi->now_idx = 0;
|
||
|
|
avi->cache_idx = 0;
|
||
|
|
}
|
||
|
|
avi_file_syn(avi->fp);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void avimuxer_sync(void *ctx)
|
||
|
|
{
|
||
|
|
AVI_FILE *avi = (AVI_FILE *) ctx;
|
||
|
|
if (avi && avi->fp)
|
||
|
|
{
|
||
|
|
avi_file_syn(avi->fp);
|
||
|
|
avimuxer_fix_data2(avi, 1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void avimuxer_exit2(void *ctx)
|
||
|
|
{
|
||
|
|
AVI_FILE *avi = (AVI_FILE *) ctx;
|
||
|
|
if (avi)
|
||
|
|
{
|
||
|
|
os_printf("avi->extern_fp:%d\n", avi->extern_fp);
|
||
|
|
if (avi->fp)
|
||
|
|
{
|
||
|
|
avimuxer_fix_data2(avi, 1);
|
||
|
|
if (!avi->extern_fp)
|
||
|
|
{
|
||
|
|
avi_close(avi->fp);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (avi->framesize_lst)
|
||
|
|
{
|
||
|
|
STREAM_FREE(avi->framesize_lst);
|
||
|
|
}
|
||
|
|
|
||
|
|
STREAM_FREE(avi);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t avimuxer_video2(void *ctx, unsigned char *buf, int len, int key, unsigned pts, uint8_t insert)
|
||
|
|
{
|
||
|
|
uint32_t ret = AVIMUXER_OK;
|
||
|
|
AVI_FILE *avi = (AVI_FILE *) ctx;
|
||
|
|
if (avi == NULL)
|
||
|
|
{
|
||
|
|
ret = AVIMUXER_ERR;
|
||
|
|
goto avimuxer_video2_end;
|
||
|
|
}
|
||
|
|
if (avi->fp)
|
||
|
|
{
|
||
|
|
int alignlen = (len & 1) ? len + 1 : len;
|
||
|
|
// 补帧,不需要写入数据
|
||
|
|
if (!insert)
|
||
|
|
{
|
||
|
|
avi_seek(avi->fp, avi->cur_addr, SEEK_SET);
|
||
|
|
if (avi_tell(avi->fp) - avi->movi_addr + alignlen > avi->movi_addr_end)
|
||
|
|
{
|
||
|
|
ret = AVIMUXER_FULL;
|
||
|
|
goto avimuxer_video2_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
avi_write("01dc", 4, 1, avi->fp);
|
||
|
|
avi_write(&alignlen, 4, 1, avi->fp);
|
||
|
|
avi_write(buf, len, 1, avi->fp);
|
||
|
|
if (len & 1)
|
||
|
|
{
|
||
|
|
avi_write((void *) &avi_zero, 1, 1, avi->fp);
|
||
|
|
}
|
||
|
|
avi->cur_addr = avi_tell(avi->fp);
|
||
|
|
if (avi->movi_addr_end - avi_tell(avi->fp) + 4 > 8)
|
||
|
|
{
|
||
|
|
// 补junk的数据
|
||
|
|
avi_write("JUNK", 4, 1, avi->fp);
|
||
|
|
// 补junk长度
|
||
|
|
uint32_t junklen = avi->movi_addr_end - avi_tell(avi->fp) - 8 + 4;
|
||
|
|
avi_write(&junklen, 4, 1, avi->fp);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (avi->cache_idx < sizeof(avi->frame_list) / 4)
|
||
|
|
{
|
||
|
|
if (insert)
|
||
|
|
{
|
||
|
|
avi->frame_list[avi->cache_idx++] = alignlen | AVI_VIDEO_FRAME | AVI_INSERT_FRAME | (key << 30);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
avi->frame_list[avi->cache_idx++] = alignlen | AVI_VIDEO_FRAME | (key << 30);
|
||
|
|
}
|
||
|
|
|
||
|
|
avi->total_idx++;
|
||
|
|
}
|
||
|
|
avi->strhdr_video.length++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 同步一次
|
||
|
|
if (avi->cache_idx == sizeof(avi->frame_list) / 4)
|
||
|
|
{
|
||
|
|
avimuxer_fix_data2(avi, 1);
|
||
|
|
avi->cache_idx = 0;
|
||
|
|
avi->cache_idx = 0;
|
||
|
|
}
|
||
|
|
avimuxer_video2_end:
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t avimuxer_audio2(void *ctx, unsigned char *buf, int len, int key, unsigned pts)
|
||
|
|
{
|
||
|
|
uint32_t ret = AVIMUXER_OK;
|
||
|
|
AVI_FILE *avi = (AVI_FILE *) ctx;
|
||
|
|
if (avi && avi->fp)
|
||
|
|
{
|
||
|
|
int alignlen = (len & 1) ? len + 1 : len;
|
||
|
|
avi_seek(avi->fp, avi->cur_addr, SEEK_SET);
|
||
|
|
if (avi_tell(avi->fp) - avi->movi_addr + alignlen > avi->movi_addr_end)
|
||
|
|
{
|
||
|
|
ret = AVIMUXER_FULL;
|
||
|
|
goto avimuxer_audio2_end;
|
||
|
|
}
|
||
|
|
avi_write("00wb", 4, 1, avi->fp);
|
||
|
|
avi_write(&alignlen, 4, 1, avi->fp);
|
||
|
|
avi_write(buf, len, 1, avi->fp);
|
||
|
|
if (len & 1)
|
||
|
|
{
|
||
|
|
avi_write((void *) &avi_zero, 1, 1, avi->fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
avi->cur_addr = avi_tell(avi->fp);
|
||
|
|
if (avi->movi_addr_end - avi_tell(avi->fp) + 4 > 8)
|
||
|
|
{
|
||
|
|
// 补junk的数据
|
||
|
|
avi_write("JUNK", 4, 1, avi->fp);
|
||
|
|
// 补junk长度
|
||
|
|
uint32_t junklen = avi->movi_addr_end - avi_tell(avi->fp) - 8 + 4;
|
||
|
|
avi_write(&junklen, 4, 1, avi->fp);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (avi->cache_idx < sizeof(avi->frame_list) / 4)
|
||
|
|
{
|
||
|
|
avi->frame_list[avi->cache_idx++] = alignlen | AVI_AUDIO_FRAME;
|
||
|
|
avi->total_idx++;
|
||
|
|
}
|
||
|
|
|
||
|
|
avi->strhdr_audio.length += (len >> 1);
|
||
|
|
}
|
||
|
|
// 同步一次
|
||
|
|
if (avi->cache_idx == sizeof(avi->frame_list) / 4)
|
||
|
|
{
|
||
|
|
avimuxer_fix_data2(avi, 1);
|
||
|
|
avi->cache_idx = 0;
|
||
|
|
}
|
||
|
|
avimuxer_audio2_end:
|
||
|
|
return 0;
|
||
|
|
}
|