/* 数据写入文件 */
int mp4_storage_save_mp4(struct storage_write_buf *write_buf,
#ifdef DUAL_CAM
struct storage_write_buf *video2_write_buf,
#endif
struct storage_write_buf *ext_write_buf,
unsigned int event_type_count)
{
MP4MUXCONTEXT *p_mp4_mux_context = &(g_mp4_storage.mp4_mux_context);
PTR_FRAME_HEAD_S p_frame_head = NULL;
unsigned char *p_frame_data = NULL;
unsigned int current_size = 0;
unsigned int frame_size = 0;
long long frame_timestamp = 0LL;
unsigned int audio_current_size = 0;
PTR_FRAME_HEAD_S p_prev_video_frame_head = NULL;
unsigned char *p_prev_video_frame_data = NULL;
long long prev_video_timestamp = 0;
BOOL file_cache_dropped = FALSE;
unsigned char *p_gop_buf = write_buf->buf;
unsigned int gop_size = write_buf->len;
unsigned char *p_audio_gop_buf = ext_write_buf->buf;
unsigned int audio_gop_size = ext_write_buf->len;
#ifdef DUAL_CAM
unsigned int video2_current_size = 0;
unsigned char *p_video2_gop_buf = video2_write_buf->buf;
unsigned int video2_gop_size = video2_write_buf->len;
#endif
#ifdef VIDEO_AVBR_ENABLE
unsigned char *p_i_frame_buf = write_buf->i_frame_buf;
PTR_FRAME_HEAD_S tmp_p_frame_head = NULL;
unsigned char *tmp_p_frame_data = NULL;
FRAME_HEAD_S tmp_frame_head_content;
memset(&tmp_frame_head_content, 0, sizeof(FRAME_HEAD_S));
FRAME_HEAD_S tmp_frame_head_content_second;
memset(&tmp_frame_head_content_second, 0, sizeof(FRAME_HEAD_S));
FRAME_HEAD_S tmp_frame_head_content_second_prev;
memset(&tmp_frame_head_content_second_prev, 0, sizeof(FRAME_HEAD_S));
#endif
int type = MP4_STORAGE_FRAME_TYPE_COUNT;
int ret = MP4MUX_EC_OK;
int result = 0;
if (p_gop_buf == NULL)
{
return ERROR;
}
LOCK(&(g_mp4_storage.mutex));
/* MP4 context已经被释放,直接退出 */
if (g_mp4_storage.if_mp4_context_initial == 0)
{
ret = OK;
goto end;
}
/* 如果是第一个GOP,需要确保I帧第一个被处理,再检查I帧之后是否存在时间戳比其小的音频帧,有则丢弃 */
if (g_mp4_storage.if_first_gop)
{
g_mp4_storage.if_first_gop = 0;
p_frame_head = (PTR_FRAME_HEAD_S) p_gop_buf;
p_frame_data = (unsigned char *) p_frame_head + sizeof(FRAME_HEAD_S);
frame_timestamp = ntohll(p_frame_head->timestamp);
frame_size = ntohl(p_frame_head->data_len);
/* 先处理I帧 */
#ifdef VIDEO_AVBR_ENABLE
if (!p_i_frame_buf)
{
if (p_frame_head->video_frame_type == TP_FRAME_TYPE_VIRTUAL_I)
{
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_VIRTUAL_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_VIRTUAL_I;
}
}
else
{
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_I;
}
}
}
else
{
tmp_p_frame_head = (PTR_FRAME_HEAD_S) p_i_frame_buf;
/* To avoid that the difference of timestamp of first video and audio frame is too big,
* let timestamp of only decoding I frame be 1 millisecond smaller than timestamp of virtual I frame.
*/
memcpy(&tmp_frame_head_content, tmp_p_frame_head, sizeof(FRAME_HEAD_S));
tmp_frame_head_content.timestamp = ntohll(p_frame_head->timestamp) - 1000;
tmp_frame_head_content.timestamp = htonll(tmp_frame_head_content.timestamp);
tmp_p_frame_data = p_i_frame_buf + sizeof(FRAME_HEAD_S);
ret = mp4_storage_do_saving_mp4(MP4_STORAGE_FRAME_TYPE_VIDEO_ONLY_DECODING_I,
&tmp_frame_head_content, tmp_p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving only decoding I frame failed");
goto end;
}
if (event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_VIRTUAL_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_VIRTUAL_I;
}
}
#else
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_I;
}
#endif
if (event_type_count > 0)
{
p_frame_head->reserve1 = event_type_count;
}
ret = mp4_storage_do_saving_mp4(type, p_frame_head, p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving I or virtual I frame failed");
goto end;
}
/* 再处理GOP中其余帧 */
current_size += (sizeof(FRAME_HEAD_S) + frame_size);
current_size = ALIGN(current_size, FRAME_ALIGN_SIZE);
prev_video_timestamp = frame_timestamp;
while (audio_current_size < audio_gop_size)
{
p_frame_head = (PTR_FRAME_HEAD_S) (p_audio_gop_buf + audio_current_size);
frame_timestamp = ntohll(p_frame_head->timestamp);
frame_size = ntohl(p_frame_head->data_len);
if (frame_timestamp >= prev_video_timestamp)
{
break; // 找到第一个时间戳大于I帧的音频帧,可以退出继续处理了
}
STM_DEBUG("Find a audio frame after I frame which has smaller timestamp (%lld) than "
"I frame's (%lld)", frame_timestamp, prev_video_timestamp);
audio_current_size += (sizeof(FRAME_HEAD_S) + frame_size);
audio_current_size = ALIGN(audio_current_size, FRAME_ALIGN_SIZE);
}
}
/*
* 对每一个视频GOP的帧,先处理时间戳比其小的音频GOP里的音频帧,然后再处理该视频帧
*/
while (current_size < gop_size)
{
p_frame_head = (PTR_FRAME_HEAD_S) (p_gop_buf + current_size);
frame_timestamp = ntohll(p_frame_head->timestamp);
frame_size = ntohl(p_frame_head->data_len);
p_prev_video_frame_head = p_frame_head;
p_prev_video_frame_data = (unsigned char *) p_frame_head + sizeof(FRAME_HEAD_S);
prev_video_timestamp = frame_timestamp;
/* 先寻找时间戳比该视频帧小的音频帧 */
current_size += (sizeof(FRAME_HEAD_S) + frame_size);
current_size = ALIGN(current_size, FRAME_ALIGN_SIZE);
while (audio_current_size < audio_gop_size)
{
p_frame_head = (PTR_FRAME_HEAD_S) (p_audio_gop_buf + audio_current_size);
frame_timestamp = ntohll(p_frame_head->timestamp);
frame_size = ntohl(p_frame_head->data_len);
/* 找到时间戳比视频帧小的音频帧进行处理 */
if (frame_timestamp < prev_video_timestamp)
{
STM_DEBUG("Find a audio frame after video frame which has smaller timestamp (%lld) "
"than video frame's (type: %u, timestamp: %lld)", frame_timestamp,
p_prev_video_frame_head->video_frame_type, prev_video_timestamp);
p_frame_data = (unsigned char *) p_frame_head + sizeof(FRAME_HEAD_S);
ret = mp4_storage_do_saving_mp4(MP4_STORAGE_FRAME_TYPE_AUDIO, p_frame_head,
p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving audio frame failed");
goto end;
}
}
else
{
break;
}
audio_current_size += (sizeof(FRAME_HEAD_S) + frame_size);
audio_current_size = ALIGN(audio_current_size, FRAME_ALIGN_SIZE);
}
#ifdef DUAL_CAM
/* 根据时间戳插入video2帧 */
while (video2_current_size < video2_gop_size)
{
p_frame_head = (PTR_FRAME_HEAD_S) (p_video2_gop_buf + video2_current_size);
frame_timestamp = ntohll(p_frame_head->timestamp);
frame_size = ntohl(p_frame_head->data_len);
/* 找到时间戳比视频帧小的音频帧进行处理 */
if (frame_timestamp < prev_video_timestamp)
{
p_frame_data = (unsigned char *) p_frame_head + sizeof(FRAME_HEAD_S);
/* 再处理视频帧 */
if (p_frame_head->video_frame_type == TP_FRAME_TYPE_P)
{
ret = mp4_storage_do_saving_mp4(MP4_STORAGE_FRAME_TYPE_VIDEO2_P, p_frame_head, p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving video2 P frame failed");
goto end;
}
}
/* I帧或伪I帧 */
else
{
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO2_NON_EVENT_START_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO2_EVENT_START_I;
}
if (event_type_count > 0)
{
p_frame_head->reserve1 = event_type_count;
}
ret = mp4_storage_do_saving_mp4(type, p_frame_head, p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving video2 I or virtual I frame failed");
goto end;
}
}
}
else
{
break;
}
video2_current_size += (sizeof(FRAME_HEAD_S) + frame_size);
video2_current_size = ALIGN(video2_current_size, FRAME_ALIGN_SIZE);
}
#endif
/* 再处理视频帧 */
if (p_prev_video_frame_head->video_frame_type == TP_FRAME_TYPE_P)
{
ret = mp4_storage_do_saving_mp4(MP4_STORAGE_FRAME_TYPE_VIDEO_P, p_prev_video_frame_head,
p_prev_video_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving P frame failed");
goto end;
}
}
/* I帧或伪I帧 */
else
{
#ifdef VIDEO_AVBR_ENABLE
if (!p_i_frame_buf)
{
if (p_prev_video_frame_head->video_frame_type == TP_FRAME_TYPE_VIRTUAL_I)
{
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_VIRTUAL_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_VIRTUAL_I;
}
}
else
{
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_I;
}
}
}
else
{
p_frame_head = (PTR_FRAME_HEAD_S) p_i_frame_buf;
/* To avoid that the difference of timestamp of first video and audio frame is too big,
* let timestamp of only decoding I frame be 1 millisecond smaller than timestamp of virtual I frame.
*/
memcpy(&tmp_frame_head_content_second, p_frame_head, sizeof(FRAME_HEAD_S));
memcpy(&tmp_frame_head_content_second_prev, p_prev_video_frame_head, sizeof(FRAME_HEAD_S));
tmp_frame_head_content_second.timestamp = ntohll(tmp_frame_head_content_second_prev.timestamp) - 1000;
tmp_frame_head_content_second.timestamp = htonll(tmp_frame_head_content_second.timestamp);
p_frame_data = p_i_frame_buf + sizeof(FRAME_HEAD_S);
ret = mp4_storage_do_saving_mp4(MP4_STORAGE_FRAME_TYPE_VIDEO_ONLY_DECODING_I,
&tmp_frame_head_content_second, p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving only decoding I frame failed");
goto end;
}
if (event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_VIRTUAL_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_VIRTUAL_I;
}
}
#else
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_NON_EVENT_START_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO_EVENT_START_I;
}
#endif
if (event_type_count > 0)
{
p_prev_video_frame_head->reserve1 = event_type_count;
}
ret = mp4_storage_do_saving_mp4(type, p_prev_video_frame_head, p_prev_video_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving I or virtual I frame failed");
goto end;
}
}
}
/* 最后处理音频GOP里可能剩余的音频帧 */
while (audio_current_size < audio_gop_size)
{
p_frame_head = (PTR_FRAME_HEAD_S) (p_audio_gop_buf + audio_current_size);
p_frame_data = (unsigned char *) p_frame_head + sizeof(FRAME_HEAD_S);
frame_size = ntohl(p_frame_head->data_len);
ret = mp4_storage_do_saving_mp4(MP4_STORAGE_FRAME_TYPE_AUDIO, p_frame_head, p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving audio frame failed");
goto end;
}
audio_current_size += (sizeof(FRAME_HEAD_S) + frame_size);
audio_current_size = ALIGN(audio_current_size, FRAME_ALIGN_SIZE);
}
#ifdef DUAL_CAM
/* 处理剩余 camera2 的 视频 */
while (video2_current_size < video2_gop_size)
{
p_frame_head = (PTR_FRAME_HEAD_S) (p_video2_gop_buf + video2_current_size);
frame_timestamp = ntohll(p_frame_head->timestamp);
frame_size = ntohl(p_frame_head->data_len);
p_frame_data = (unsigned char *) p_frame_head + sizeof(FRAME_HEAD_S);
if (p_frame_head->video_frame_type == TP_FRAME_TYPE_P)
{
ret = mp4_storage_do_saving_mp4(MP4_STORAGE_FRAME_TYPE_VIDEO2_P, p_frame_head,
p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving video2 P frame failed");
goto end;
}
}
/* I帧或伪I帧 */
else
{
if (!event_type_count)
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO2_NON_EVENT_START_I;
}
else
{
type = MP4_STORAGE_FRAME_TYPE_VIDEO2_EVENT_START_I;
}
if (event_type_count > 0)
{
p_frame_head->reserve1 = event_type_count;
}
ret = mp4_storage_do_saving_mp4(type, p_frame_head, p_frame_data);
if (ret == ERROR)
{
STM_ERROR("Saving video2 I or virtual I frame failed");
goto end;
}
}
video2_current_size += (sizeof(FRAME_HEAD_S) + frame_size);
video2_current_size = ALIGN(video2_current_size, FRAME_ALIGN_SIZE);
}
#endif
result = mp4_storage_writev(p_mp4_mux_context);
if(result < 0)
{
ret = ERROR;
}
/*
* 每次写完一个GOP数据,调用sync(不调用无法写回cache脏数据)和
* posix_fadvise刷新mp4文件对应的缓存,保持freeram不被cache占用,
* 对性能的影响待测试(目前运行没有明显区别)
*/
if(!file_cache_dropped)
{
#ifndef DUAL_CAM
drop_file_cache_range(p_mp4_mux_context->iMP4Fd,
p_mp4_mux_context->uiCurrentOffset - current_size - audio_current_size,
current_size + audio_current_size,
true);
#else
drop_file_cache_range(p_mp4_mux_context->iMP4Fd,
p_mp4_mux_context->uiCurrentOffset - current_size - audio_current_size - video2_current_size,
current_size + audio_current_size + video2_current_size,
true);
#endif
}
ret = OK;
end:
UNLOCK(&(g_mp4_storage.mutex));
return ret;
}
报错:为什么mp4_storage_save_mp4报错,但是error在mp4_storage_do_saving_mp4没有打印,不知道报错在哪里啊[ERROR] mp4_storage_save_mp4():665 - [STM]Saving video2 I or virtual I frame failed
[2025-09-16 20:05:56] [ERROR] StgMod_Write():1430 - [STM]write mp4 data fail! ret(-1)
[2025-09-16 20:05:56] record_thread_func():1909 - [STM]init_storage_data(&video2_storage_data, &video_block, 0)