From ec39775a78b7f558c49bb442aa43717943e8a31e Mon Sep 17 00:00:00 2001 From: "jiyong.min" Date: Mon, 9 Sep 2019 16:28:09 +0900 Subject: [PATCH] Improve '__mmfile_get_frame' function to reduce Cyclomatic Complexity Change-Id: Ia0335b309420605b39dadef3b63c114e94f2564d --- formats/ffmpeg/mm_file_format_frame.c | 288 ++++++++++++++++++++-------------- 1 file changed, 172 insertions(+), 116 deletions(-) diff --git a/formats/ffmpeg/mm_file_format_frame.c b/formats/ffmpeg/mm_file_format_frame.c index 7e42462..a0ae37b 100755 --- a/formats/ffmpeg/mm_file_format_frame.c +++ b/formats/ffmpeg/mm_file_format_frame.c @@ -32,9 +32,9 @@ #define MILLION 1000000 #ifdef MMFILE_FORMAT_DEBUG_DUMP -static void __save_frame(uint8_t *const dst[], const int dstStride[], int width, int height, int iFrame); +static void __save_frame(int width, int height, unsigned char *frame, int size, int iFrame); -void __save_frame(uint8_t *const dst[], const int dstStride[], int width, int height, int iFrame) +void __save_frame(int width, int height, unsigned char *frame, int size, int iFrame) { FILE *pFile; char szFilename[32] = {0,}; @@ -50,8 +50,7 @@ void __save_frame(uint8_t *const dst[], const int dstStride[], int width, int he /* Write header */ fprintf(pFile, "P6\n%d %d\n255\n", width, height); /* Write pixel data */ - for (y = 0; y < height; y++) - fwrite(dst[0] + y * dstStride[0], 1, width * 3, pFile); + fwrite(frame, 1, size, pFile); /* Close file */ fclose(pFile); @@ -279,77 +278,57 @@ FILE_FORMAT_SUCCESS: return MMFILE_FORMAT_SUCCESS; } -static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height) +static int __mmfile_get_first_video_stream(AVFormatContext *pFormatCtx, int *videoStream) { unsigned int i = 0; - int len = 0; - int ret = MMFILE_FORMAT_SUCCESS; - int videoStream = -1; - int64_t pos = timestamp; - bool find = false; - bool first_seek = true; - int64_t pts = 0; - AVCodecContext *pVideoCodecCtx = NULL; - AVCodecParameters *pVideoCodecPar = NULL; - AVCodec *pVideoCodec = NULL; - AVFrame *pFrame = NULL; - AVPacket packet; - AVStream *pStream = NULL; - double duration = 0; - int64_t tmpPts = 0; -#ifdef __MMFILE_TEST_MODE__ - int idx = 0; -#endif - /* Retrieve stream information */ - if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { - debug_error(DEBUG, "error : av_find_stream_info failed"); - ret = MMFILE_FORMAT_FAIL; - goto exception; /* Couldn't find stream information */ - } + *videoStream = -1; /* Find the first video stream */ for (i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - videoStream = i; + *videoStream = i; break; } } - if (videoStream == -1) { + if (*videoStream == -1) { debug_error(DEBUG, "error : videoStream == -1"); - ret = MMFILE_FORMAT_FAIL; - goto exception; /* Didn't find a video stream */ + return MMFILE_FORMAT_FAIL; } + return MMFILE_FORMAT_SUCCESS; +} + +static int __mmfile_open_video_codec(AVFormatContext *pFormatCtx, int videoStream, AVCodecContext **ppVideoCodecCtx) +{ + AVCodecContext *pVideoCodecCtx = NULL; + AVCodecParameters *pVideoCodecPar = NULL; + AVCodec *pVideoCodec = NULL; + /* Get a pointer to the codec context for the video stream */ pVideoCodecPar = pFormatCtx->streams[videoStream]->codecpar; - if (pVideoCodecPar == NULL) { + if (!pVideoCodecPar) { debug_error(DEBUG, "invalid param\n"); - ret = MMFILE_FORMAT_FAIL; - goto exception; + return MMFILE_FORMAT_FAIL; } /* Find the decoder for the video stream */ pVideoCodec = avcodec_find_decoder(pVideoCodecPar->codec_id); - if (pVideoCodec == NULL) { + if (!pVideoCodec) { debug_error(DEBUG, "error : Unsupported codec"); - ret = MMFILE_FORMAT_FAIL; - goto exception; /* Codec not found */ + return MMFILE_FORMAT_FAIL; } pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec); - if (NULL == pVideoCodecCtx) { + if (!pVideoCodecCtx) { debug_error(DEBUG, "error: pVideoCodecCtx == NULL\n"); - ret = MMFILE_FORMAT_FAIL; - goto exception; + return MMFILE_FORMAT_FAIL; } - ret = avcodec_parameters_to_context(pVideoCodecCtx, pVideoCodecPar); - if (ret < 0) { + if (avcodec_parameters_to_context(pVideoCodecCtx, pVideoCodecPar) < 0) { debug_error(DEBUG, "error: avcodec_parameters_to_context\n"); - ret = MMFILE_FORMAT_FAIL; - goto exception; + return MMFILE_FORMAT_FAIL; } /*set workaround bug flag*/ @@ -360,21 +339,18 @@ static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bo pVideoCodecCtx->thread_count = 0; if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) { debug_error(DEBUG, "error : avcodec_open failed"); - ret = MMFILE_FORMAT_FAIL; - goto exception;; /*Could not open codec */ + return MMFILE_FORMAT_FAIL; } - /* Storing Data */ - /* Allocate video frame */ - pFrame = av_frame_alloc(); - if (pFrame == NULL) { - debug_error(DEBUG, "error: pFrame is NULL\n"); - ret = MMFILE_FORMAT_FAIL; - goto exception; - } + *ppVideoCodecCtx = pVideoCodecCtx; + + return MMFILE_FORMAT_SUCCESS; +} + +static int __mmfile_seek_to_pos(AVFormatContext *pFormatCtx, int64_t pos, bool is_accurate) +{ + double duration = 0; - /* Seeking */ - pStream = pFormatCtx->streams[videoStream]; duration = (double) pFormatCtx->duration / AV_TIME_BASE; #if 0 if (duration <= 0) { @@ -392,8 +368,7 @@ static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bo duration = duration * MILLION; if ((duration <= 0) || (duration <= pos)) { debug_error(DEBUG, "duration error duration[%f] pos[%"PRId64"]", duration, pos); - ret = MMFILE_FORMAT_FAIL; - goto exception; + return MMFILE_FORMAT_FAIL; } if (is_accurate) @@ -401,17 +376,32 @@ static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bo else av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD); - /* Reading Data */ + return MMFILE_FORMAT_SUCCESS; +} +static bool __mmfile_find_proper_frame(AVFormatContext *pFormatCtx, int videoStream, AVCodecContext *pVideoCodecCtx, int64_t pos, bool is_accurate, AVFrame *pFrame) +{ + bool find = false; + AVPacket packet; + AVStream *pStream = NULL; + bool first_seek = true; + int64_t pts = 0; + int64_t tmpPts = 0; + int len = 0; +#ifdef __MMFILE_TEST_MODE__ + int idx = 0; +#endif + + pStream = pFormatCtx->streams[videoStream]; av_init_packet(&packet); while (av_read_frame(pFormatCtx, &packet) >= 0) { /* Is this a packet from the video stream? */ if (packet.stream_index == videoStream) { - #ifdef __MMFILE_TEST_MODE__ + #ifdef __MMFILE_TEST_MODE__ debug_msg(RELEASE, "find Video Stream+++++++[%2d]", idx++); - #endif + #endif /* Decode video frame*/ len = avcodec_send_packet(pVideoCodecCtx, &packet); @@ -473,76 +463,142 @@ static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bo /*free pkt after loop breaking*/ av_packet_unref(&packet); - /* Did we get a video frame?*/ - if (find) { + return find; +} - debug_msg(RELEASE, "Find Frame"); +static int __mmfile_swscale_frame(AVCodecContext *pVideoCodecCtx, AVFrame *pFrame, int width, int height, unsigned char *frame, int size) +{ + int ret = MMFILE_FORMAT_SUCCESS; + int av_err = 0; + uint8_t *dst_data[4]; + int dst_linesize[4]; + struct SwsContext *img_convert_ctx = NULL; + + av_err = av_image_fill_arrays(dst_data, dst_linesize, frame, AV_PIX_FMT_RGB24, width, height, 1); + if (av_err < 0) { + debug_error(DEBUG, "error: avpicture_fill fail. errcode = 0x%08X\n", ret); + ret = MMFILE_FORMAT_FAIL; + goto exception; + } - /* return frame infromations*/ - if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) { - *width = pVideoCodecCtx->coded_width; - *height = pVideoCodecCtx->coded_height; - } else { - *width = pVideoCodecCtx->width; - *height = pVideoCodecCtx->height; - } + img_convert_ctx = sws_getContext(width, height, pVideoCodecCtx->pix_fmt, width, height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); - *size = av_image_get_buffer_size(AV_PIX_FMT_RGB24, *width, *height, 1); + if (!img_convert_ctx) { + debug_error(DEBUG, "failed to get img convet ctx\n"); + ret = MMFILE_FORMAT_FAIL; + goto exception; + } - if (*size > 0) - *frame = mmfile_malloc(*size); + av_err = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize, 0, height, dst_data, dst_linesize); + if (av_err < 0) { + debug_error(DEBUG, "failed to convet image\n"); + ret = MMFILE_FORMAT_FAIL; + goto exception; + } +exception: + sws_freeContext(img_convert_ctx); + img_convert_ctx = NULL; - if (NULL == *frame) { - debug_error(DEBUG, "error: avpicture_get_size. [%d]\n", *size); - ret = MMFILE_FORMAT_FAIL; - goto exception; - } + return ret; +} - debug_msg(RELEASE, "size : %d", *size); - debug_msg(RELEASE, "width : %d", *width); - debug_msg(RELEASE, "height : %d", *height); - debug_msg(RELEASE, "frame : %p", *frame); - - uint8_t *dst_data[4]; - int dst_linesize[4]; - ret = av_image_fill_arrays(dst_data, dst_linesize, *frame, AV_PIX_FMT_RGB24, *width, *height, 1); - if (ret < 0) { - debug_error(DEBUG, "error: avpicture_fill fail. errcode = 0x%08X\n", ret); - ret = MMFILE_FORMAT_FAIL; - goto exception; - } +static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height) +{ + int ret = MMFILE_FORMAT_SUCCESS; + int videoStream = -1; + AVCodecContext *pVideoCodecCtx = NULL; + bool find = false; + AVFrame *pFrame = NULL; + + /* Retrieve stream information */ + if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { + debug_error(DEBUG, "error : av_find_stream_info failed"); + ret = MMFILE_FORMAT_FAIL; + goto exception; /* Couldn't find stream information */ + } + + /* Find the first video stream */ + ret = __mmfile_get_first_video_stream(pFormatCtx, &videoStream); + if (MMFILE_FORMAT_FAIL == ret) { + debug_error(DEBUG, "error : __mmfile_get_first_video_stream"); + goto exception; /* Didn't find a video stream */ + } - struct SwsContext *img_convert_ctx = NULL; + ret = __mmfile_open_video_codec(pFormatCtx, videoStream, &pVideoCodecCtx); + if (MMFILE_FORMAT_FAIL == ret) { + debug_error(DEBUG, "error : __mmfile_open_video_codec"); + goto exception; /*Could not open codec */ + } - img_convert_ctx = sws_getContext(*width, *height, pVideoCodecCtx->pix_fmt, *width, *height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); + /* Storing Data */ + /* Allocate video frame */ + pFrame = av_frame_alloc(); + if (!pFrame) { + debug_error(DEBUG, "error: pFrame is NULL\n"); + ret = MMFILE_FORMAT_FAIL; + goto exception; + } - if (NULL == img_convert_ctx) { - debug_error(DEBUG, "failed to get img convet ctx\n"); - ret = MMFILE_FORMAT_FAIL; - goto exception; - } + /* Seeking */ + ret = __mmfile_seek_to_pos(pFormatCtx, timestamp, is_accurate); + if (MMFILE_FORMAT_FAIL == ret) { + debug_error(DEBUG, "error : __mmfile_seek_to_pos"); + goto exception; /*Could not seek to timestamp */ + } - ret = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize, 0, *height, dst_data, dst_linesize); - if (ret < 0) { - debug_error(DEBUG, "failed to convet image\n"); - sws_freeContext(img_convert_ctx); - img_convert_ctx = NULL; - ret = MMFILE_FORMAT_FAIL; - goto exception; - } + /* Reading Data */ + find = __mmfile_find_proper_frame(pFormatCtx, videoStream, pVideoCodecCtx, timestamp, is_accurate, pFrame); - sws_freeContext(img_convert_ctx); - img_convert_ctx = NULL; + /* Did we get a video frame?*/ + if (!find) { + debug_error(DEBUG, "Not Found Proper Frame[%d]", find); + ret = MMFILE_FORMAT_FAIL; + goto exception; + } -#ifdef MMFILE_FORMAT_DEBUG_DUMP - __save_frame(dst_data, dst_linesize, pVideoCodecCtx->width, pVideoCodecCtx->height, (int)(pos / 1000)); -#endif + debug_msg(RELEASE, "Find Frame"); + + /* return frame infromations*/ + if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) { + *width = pVideoCodecCtx->coded_width; + *height = pVideoCodecCtx->coded_height; } else { - debug_error(DEBUG, "Not Found Proper Frame[%d]", find); + *width = pVideoCodecCtx->width; + *height = pVideoCodecCtx->height; + } + + *size = av_image_get_buffer_size(AV_PIX_FMT_RGB24, *width, *height, 1); + + if (*size <=0 ) { + debug_error(DEBUG, "error: av_image_get_buffer_size. [%d]\n", *size); ret = MMFILE_FORMAT_FAIL; goto exception; } + *frame = mmfile_malloc(*size); + if (!(*frame)) { + debug_error(DEBUG, "error: avpicture_get_size. [%d]\n", *size); + ret = MMFILE_FORMAT_FAIL; + goto exception; + } + + debug_msg(RELEASE, "size : %d", *size); + debug_msg(RELEASE, "width : %d", *width); + debug_msg(RELEASE, "height : %d", *height); + debug_msg(RELEASE, "frame : %p", *frame); + + ret = __mmfile_swscale_frame(pVideoCodecCtx, pFrame, *width, *height, *frame, *size); + if (MMFILE_FORMAT_FAIL == ret) { + debug_error(DEBUG, "error : __mmfile_scale_frame"); + ret = MMFILE_FORMAT_FAIL; + goto exception; + } + +#ifdef MMFILE_FORMAT_DEBUG_DUMP + __save_frame(*width, *height, *frame, *size, (int)(timestamp / 1000)); +#endif + debug_msg(RELEASE, "frame : %p", *frame); + if (pFrame) av_frame_free(&pFrame); if (pVideoCodecCtx) avcodec_free_context(&pVideoCodecCtx); -- 2.7.4