4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Haejeong Kim <backto.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
25 #include <libavformat/avformat.h>
26 #include <libavcodec/avcodec.h>
27 #include <libavutil/imgutils.h>
28 #include <libswscale/swscale.h>
31 #include "mm_file_debug.h"
32 #include "mm_file_formats.h"
33 #include "mm_file_utils.h"
34 #include "mm_file_format_ffmpeg.h"
36 static int g_max_analyze_duration = 0;
37 static int g_probesize = 0;
39 #ifdef __MMFILE_TEST_MODE__
40 static void _dump_av_packet(AVPacket *pkt)
42 debug_msg(RELEASE, "--------- AV Packet -----------");
43 debug_msg(RELEASE, " pts: %lld", pkt->pts);
44 debug_msg(RELEASE, " dts: %lld", pkt->dts);
45 debug_msg(RELEASE, " data: %p", pkt->data);
46 debug_msg(RELEASE, " size: %d", pkt->size);
47 debug_msg(RELEASE, " stream_index: %d", pkt->stream_index);
48 debug_msg(RELEASE, " flags: 0x%08X, %s", pkt->flags, (pkt->flags & AV_PKT_FLAG_KEY) ? "Keyframe" : "_");
49 debug_msg(RELEASE, " duration: %lld", pkt->duration);
50 /*debug_msg(RELEASE, " destruct: %p", pkt->destruct);*/
51 /*debug_msg(RELEASE, " priv: %p", pkt->priv);*/
52 debug_msg(RELEASE, " pos: %lld", pkt->pos);
53 debug_msg(RELEASE, "-------------------------------");
57 static int _get_first_good_video_frame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, AVFrame **pFrame, int cdis);
59 static int __convert_vidio_codec_type(int AVVideoCodecID)
61 switch (AVVideoCodecID) {
62 case AV_CODEC_ID_MPEG1VIDEO:
63 return MM_VIDEO_CODEC_MPEG1;
64 case AV_CODEC_ID_MPEG2VIDEO: /*/< preferred ID for MPEG-1/2 video decoding */
65 case AV_CODEC_ID_MPEG2TS:
66 return MM_VIDEO_CODEC_MPEG2;
67 case AV_CODEC_ID_H261:
68 return MM_VIDEO_CODEC_H261;
69 case AV_CODEC_ID_H263:
70 return MM_VIDEO_CODEC_H263;
71 case AV_CODEC_ID_MPEG4:
72 case AV_CODEC_ID_MSMPEG4V1:
73 case AV_CODEC_ID_MSMPEG4V2:
74 case AV_CODEC_ID_MSMPEG4V3:
75 return MM_VIDEO_CODEC_MPEG4;
76 case AV_CODEC_ID_WMV1:
77 case AV_CODEC_ID_WMV2:
78 return MM_VIDEO_CODEC_WMV;
79 case AV_CODEC_ID_H263P:
80 case AV_CODEC_ID_H263I:
81 return MM_VIDEO_CODEC_H263;
82 case AV_CODEC_ID_FLV1:
83 return MM_VIDEO_CODEC_FLV;
84 case AV_CODEC_ID_H264:
85 return MM_VIDEO_CODEC_H264;
86 case AV_CODEC_ID_INDEO2:
87 case AV_CODEC_ID_INDEO3:
88 case AV_CODEC_ID_INDEO4:
89 case AV_CODEC_ID_INDEO5:
90 return MM_VIDEO_CODEC_INDEO;
91 case AV_CODEC_ID_THEORA:
92 return MM_VIDEO_CODEC_THEORA;
93 case AV_CODEC_ID_CINEPAK:
94 return MM_VIDEO_CODEC_CINEPAK;
96 return MM_VIDEO_CODEC_VC1;
97 case AV_CODEC_ID_WMV3:
98 return MM_VIDEO_CODEC_WMV;
100 return MM_VIDEO_CODEC_AVS;
101 case AV_CODEC_ID_RL2:
102 case AV_CODEC_ID_RV10: /* RealVideo 1 */
103 case AV_CODEC_ID_RV20: /* RealVideo 2 */
104 case AV_CODEC_ID_RV30: /* RealVideo 3 */
105 case AV_CODEC_ID_RV40: /* RealVideo 4 */
106 return MM_VIDEO_CODEC_REAL;
107 case AV_CODEC_ID_AV1: /* AOMedia Video 1 */
108 return MM_VIDEO_CODEC_AV1;
109 case AV_CODEC_ID_HEVC:
110 return MM_VIDEO_CODEC_MPEG4;
112 case AV_CODEC_ID_VP8:
113 return MM_VIDEO_CODEC_VP8;
114 case AV_CODEC_ID_VP9:
115 return MM_VIDEO_CODEC_VP9;
118 return MM_VIDEO_CODEC_NONE;
122 static int __convert_audio_codec_type(int AVAudioCodecID)
124 switch (AVAudioCodecID) {
125 case AV_CODEC_ID_AMR_NB:
126 case AV_CODEC_ID_AMR_WB:
127 return MM_AUDIO_CODEC_AMR;
128 /* RealAudio codecs*/
129 case AV_CODEC_ID_RA_144: /* RealAudio 1 */
130 case AV_CODEC_ID_RA_288: /* RealAudio 2 */
131 case AV_CODEC_ID_COOK: /* RealAudio 6 */
132 return MM_AUDIO_CODEC_REAL;
133 case AV_CODEC_ID_MP2:
134 return MM_AUDIO_CODEC_MP2;
135 case AV_CODEC_ID_MP3:
136 case AV_CODEC_ID_MP3ADU:
137 case AV_CODEC_ID_MP3ON4:
138 return MM_AUDIO_CODEC_MP3;
139 case AV_CODEC_ID_AAC:
140 return MM_AUDIO_CODEC_AAC;
141 case AV_CODEC_ID_AC3:
142 return MM_AUDIO_CODEC_AC3;
143 case AV_CODEC_ID_VORBIS:
144 return MM_AUDIO_CODEC_VORBIS;
145 case AV_CODEC_ID_WMAV1:
146 case AV_CODEC_ID_WMAV2:
147 case AV_CODEC_ID_WMAVOICE:
148 case AV_CODEC_ID_WMAPRO:
149 case AV_CODEC_ID_WMALOSSLESS:
150 return MM_AUDIO_CODEC_WMA;
151 case AV_CODEC_ID_FLAC:
152 return MM_AUDIO_CODEC_FLAC;
153 case AV_CODEC_ID_ALAC:
154 return MM_AUDIO_CODEC_ALAC;
155 case AV_CODEC_ID_WAVPACK:
156 return MM_AUDIO_CODEC_WAVE;
157 case AV_CODEC_ID_ATRAC3:
158 case AV_CODEC_ID_ATRAC3P:
159 case AV_CODEC_ID_EAC3:
160 return MM_AUDIO_CODEC_AC3;
161 case AV_CODEC_ID_PCM_S8:
162 case AV_CODEC_ID_PCM_S16BE:
163 case AV_CODEC_ID_PCM_S24BE:
164 case AV_CODEC_ID_PCM_S32BE:
165 return MM_AUDIO_CODEC_PCM;
167 return MM_AUDIO_CODEC_NONE;
171 /* plugin manadatory API */
172 int mmfile_format_read_stream_ffmpg(MMFileFormatContext *formatContext);
173 int mmfile_format_read_frame_ffmpg(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
174 int mmfile_format_read_tag_ffmpg(MMFileFormatContext *formatContext);
175 int mmfile_format_close_ffmpg(MMFileFormatContext *formatContext);
177 static void __count_stream_num(AVFormatContext *pFormatCtx, MMFileFormatContext *formatContext)
181 formatContext->videoTotalTrackNum = 0;
182 formatContext->audioTotalTrackNum = 0;
184 for (i = 0; i < pFormatCtx->nb_streams; i++) {
185 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
186 debug_msg(RELEASE, "FFMPEG video codec id: 0x%08X", pFormatCtx->streams[i]->codecpar->codec_id);
188 AVPacket pkt = pFormatCtx->streams[i]->attached_pic;
189 if ((pkt.data != NULL) && (pkt.size > 0))
192 /*eventhough codec_id is 0, avformat_find_stream_info() can find proper codec_id. */
193 formatContext->videoTotalTrackNum += 1;
195 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
196 debug_msg(RELEASE, "FFMPEG audio codec id: 0x%08X", pFormatCtx->streams[i]->codecpar->codec_id);
197 formatContext->audioTotalTrackNum += 1;
202 static bool __mmf_mem_open(MMFmemIOHandle **handle, const char *filename)
204 MMFmemIOHandle *memHandle = NULL;
205 char **splitedString = NULL;
207 filename += strlen(MMFILE_MEM_URI);
208 splitedString = g_strsplit(filename, ":", -1);
210 if (g_strv_length(splitedString) < 2) {
211 debug_error(DEBUG, "invalid param");
212 g_strfreev(splitedString);
217 memHandle = g_new0(MMFmemIOHandle, 1);
219 /*memory allocation address changed. memHandle->ptr = (unsigned char*)atoi(splitedString[0]); */
220 memHandle->ptr = (unsigned char *)atoll(splitedString[0]);
221 memHandle->size = atoi(splitedString[1]);
222 memHandle->offset = 0;
223 memHandle->state = 0;
227 g_strfreev(splitedString);
232 static int __mmf_mem_read(void *opaque, uint8_t *buf, int size)
234 MMFmemIOHandle *memHandle = NULL;
235 const unsigned char *c = NULL;
238 mm_file_retvm_if_fails(DEBUG, opaque, MMFILE_UTIL_FAIL);
239 mm_file_retvm_if_fails(DEBUG, buf, MMFILE_UTIL_FAIL);
243 mm_file_retvm_if_fails(DEBUG, memHandle->ptr, MMFILE_UTIL_FAIL);
244 mm_file_retvm_if_fails(DEBUG, memHandle->offset < memHandle->size, MMFILE_UTIL_FAIL);
246 c = memHandle->ptr + memHandle->offset;
248 if (memHandle->state != EOF) {
250 if (len + memHandle->offset > memHandle->size)
251 len = memHandle->size - memHandle->offset;
255 memHandle->offset += len;
257 if (memHandle->offset == memHandle->size)
258 memHandle->state = EOF;
263 static int64_t __mmf_mem_seek(void *opaque, int64_t pos, int whence)
265 MMFmemIOHandle *memHandle = NULL;
266 long long tmp_offset = 0;
268 mm_file_retvm_if_fails(DEBUG, opaque, MMFILE_UTIL_FAIL);
274 tmp_offset = 0 + pos;
277 tmp_offset = memHandle->offset + pos;
280 tmp_offset = memHandle->size + pos;
282 case AVSEEK_SIZE: /*FFMPEG specific*/
283 return memHandle->size;
285 return MMFILE_UTIL_FAIL;
289 mm_file_retvm_if_fails(DEBUG, tmp_offset >= 0 && tmp_offset <= memHandle->size, MMFILE_UTIL_FAIL);
292 memHandle->state = (tmp_offset >= memHandle->size) ? EOF : !EOF;
293 memHandle->offset = (unsigned int) tmp_offset;
299 int mmfile_format_open_ffmpg(MMFileFormatContext *formatContext)
301 AVFormatContext *pFormatCtx = NULL;
302 AVInputFormat *grab_iformat = NULL;
303 char ffmpegFormatName[MMFILE_FILE_FMT_MAX_LEN] = {0, };
304 AVIOContext *pIOCtx = NULL;
305 MMFmemIOHandle *handle = NULL;
306 uint8_t *avio_ctx_buffer = NULL;
308 formatContext->ReadStream = mmfile_format_read_stream_ffmpg;
309 formatContext->ReadFrame = mmfile_format_read_frame_ffmpg;
310 formatContext->ReadTag = mmfile_format_read_tag_ffmpg;
311 formatContext->Close = mmfile_format_close_ffmpg;
313 debug_msg(RELEASE, "ffmpeg version: %d", avformat_version());
324 #ifdef __MMFILE_TEST_MODE__
325 av_log_set_level(AV_LOG_TRACE);
327 av_log_set_level(AV_LOG_QUIET);
330 if (formatContext->filesrc->type == MM_FILE_SRC_TYPE_MEMORY) {
331 if (mmfile_util_get_ffmpeg_format(formatContext->filesrc->memory.format, ffmpegFormatName) != MMFILE_UTIL_SUCCESS) {
332 debug_error(DEBUG, "error: mmfile_util_get_ffmpeg_format");
333 return MMFILE_FORMAT_FAIL;
336 grab_iformat = av_find_input_format(ffmpegFormatName);
337 mm_file_retvm_if_fails(DEBUG, grab_iformat, MMFILE_UTIL_FAIL);
339 avio_ctx_buffer = av_malloc(MMFILE_AVIO_BUFFER_LEN);
340 mm_file_retvm_if_fails(DEBUG, avio_ctx_buffer, MMFILE_UTIL_FAIL);
342 if (!__mmf_mem_open(&handle, formatContext->uriFileName)) {
343 debug_error(DEBUG, "failed to _mmf_mem_open.");
347 pIOCtx = avio_alloc_context(avio_ctx_buffer, MMFILE_AVIO_BUFFER_LEN, 0, handle, __mmf_mem_read, NULL, __mmf_mem_seek);
349 debug_error(DEBUG, "error: cannot alloc io context");
353 pFormatCtx = avformat_alloc_context();
355 debug_error(DEBUG, "failed to avformat_alloc_context");
359 pFormatCtx->pb = pIOCtx;
361 if (avformat_open_input(&pFormatCtx, "", grab_iformat, NULL) < 0) {
362 debug_error(DEBUG, "error: cannot open %s", formatContext->uriFileName);
366 formatContext->privateFormatData = pFormatCtx;
369 if (formatContext->filesrc->type == MM_FILE_SRC_TYPE_FILE) {
370 if (avformat_open_input(&pFormatCtx, formatContext->filesrc->file.path, NULL, NULL) < 0) {
371 debug_error(DEBUG, "error: cannot open %s", formatContext->filesrc->file.path);
375 formatContext->privateFormatData = pFormatCtx;
379 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.");
383 debug_msg(RELEASE, "number of stream: %d", pFormatCtx->nb_streams);
385 __count_stream_num(pFormatCtx, formatContext);
387 debug_msg(RELEASE, "format: %s (%s)", pFormatCtx->iformat->name, pFormatCtx->iformat->long_name);
388 #ifdef __MMFILE_TEST_MODE__
389 av_dump_format(pFormatCtx, 0, formatContext->filesrc->file.path, 0);
392 return MMFILE_FORMAT_SUCCESS;
394 exception: /* fail to get content information */
395 if (formatContext->filesrc->type == MM_FILE_SRC_TYPE_MEMORY) {
397 av_free(avio_ctx_buffer);
404 avformat_close_input(&pFormatCtx);
406 mmfile_format_close_ffmpg(formatContext);
409 formatContext->privateFormatData = NULL;
411 return MMFILE_FORMAT_FAIL;
414 static int __get_video_fps(int frame_cnt, int duration, AVRational r_frame_rate, int is_roundup)
418 debug_msg(RELEASE, "frame count: %d, dur: %d, num: %d, den: %d", frame_cnt, duration, r_frame_rate.num, r_frame_rate.den);
420 if (duration <= 0 || r_frame_rate.num <= 0 || r_frame_rate.den <= 0)
423 round = (is_roundup != 0 ? 0.50f : 0.00f);
425 fps = (double)frame_cnt / ((double)(duration * r_frame_rate.num) / r_frame_rate.den) + round;
430 static bool __check_uhqa(int sample_rate, enum AVSampleFormat sample_fmt_info)
432 debug_error(RELEASE, "[sample rate %d, sample format %d]", sample_rate, sample_fmt_info);
434 if (sample_rate >= 44100 && sample_fmt_info >= AV_SAMPLE_FMT_S32) {
435 debug_msg(RELEASE, "UHQA CONTENT");
442 int mmfile_format_read_stream_ffmpg(MMFileFormatContext *formatContext)
444 AVFormatContext *pFormatCtx = NULL;
445 AVCodecParameters *pAudioCodecCtx = NULL;
446 AVCodecParameters *pVideoCodecCtx = NULL;
447 MMFileFormatStream *videoStream = NULL;
448 MMFileFormatStream *audioStream = NULL;
451 mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
452 mm_file_retvm_if_fails(DEBUG, formatContext->privateFormatData, MMFILE_FORMAT_FAIL);
454 pFormatCtx = formatContext->privateFormatData;
455 pFormatCtx->start_time = -1;
458 * If you could not find codec parameters for stream info,
459 * consider increasing the value for the 'analyzeduration' and 'probesize' options.
462 *@important if data is corrupted, occur segment fault by av_find_stream_info().
463 * - fixed 2009-06-25.
467 * if the content is 8k, the mem-usage in avformat_find_stream_info() is too large, 300MB or more.
468 * so we adjust 'probesize' to reduce memory usage in avformat_find_stream_info().
469 * Please refer to below for detail.
470 * https://ffmpeg.org/ffmpeg-formats.html#Format-Options
472 if (g_max_analyze_duration == 0)
473 g_max_analyze_duration = mmfile_get_int_from_ini(MMFILE_INI_MAXANLDURATION, MMFILE_DEFAULT_MAXANLDURATION);
474 if (g_probesize == 0)
475 g_probesize = mmfile_get_int_from_ini(MMFILE_INI_PROBESIZE, MMFILE_DEFAULT_PROBESIZE);
477 if (formatContext->formatType == MM_FILE_FORMAT_M2TS)
478 pFormatCtx->max_analyze_duration = g_max_analyze_duration; // MPEGTS file timeout set
480 pFormatCtx->probesize = g_probesize; // the size of the data(packet) to probe stream information
482 debug_msg(RELEASE, "max_analyze_duration: %"PRId64", probesize: %"PRId64"", pFormatCtx->max_analyze_duration, pFormatCtx->probesize);
484 if (formatContext->cdis != 1) {
485 if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
486 debug_warning(DEBUG, "failed to find stream info");
491 debug_msg(RELEASE, "FFMPEG: dur %"PRId64", start %"PRId64"", pFormatCtx->duration, pFormatCtx->start_time);
494 *@note asf has long duration bug. and Some content's start time is wrong(negative number).
495 * Generally, mpegts has wrong start time(positive large value). So skip start time for mpegts format.
497 if (pFormatCtx->start_time < 0 || formatContext->formatType == MM_FILE_FORMAT_M2TS) {
498 debug_warning(DEBUG, "Wrong Start time = %"PRId64"", pFormatCtx->start_time);
499 formatContext->duration = (long long)(pFormatCtx->duration) * 1000 / AV_TIME_BASE;
501 formatContext->duration = (long long)(pFormatCtx->duration + pFormatCtx->start_time) * 1000 / AV_TIME_BASE;
504 formatContext->videoStreamId = -1;
505 formatContext->audioStreamId = -1;
506 formatContext->nbStreams = 0;
507 formatContext->videoTotalTrackNum = 0;
508 formatContext->audioTotalTrackNum = 0;
510 for (i = 0; i < pFormatCtx->nb_streams; i++) {
511 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && formatContext->videoStreamId == -1) {
512 videoStream = g_new0(MMFileFormatStream, 1);
514 videoStream->streamType = MMFILE_VIDEO_STREAM;
515 formatContext->streams[MMFILE_VIDEO_STREAM] = videoStream;
516 formatContext->nbStreams += 1;
517 formatContext->videoStreamId = i;
518 formatContext->videoTotalTrackNum += 1;
520 pVideoCodecCtx = pFormatCtx->streams[i]->codecpar;
521 if (pVideoCodecCtx) {
522 videoStream->codecId = __convert_vidio_codec_type(pVideoCodecCtx->codec_id);
523 if (videoStream->codecId == MM_VIDEO_CODEC_NONE) {
524 debug_error(RELEASE, "Proper codec is not found in [%d] stream", i);
525 formatContext->videoStreamId = -1;
526 mmfile_free(videoStream);
527 formatContext->streams[MMFILE_VIDEO_STREAM] = NULL;
534 * 1. try to get average fps of video stream.
535 * 2. if (1) failed, try to get fps of media container.
537 videoStream->framePerSec = __get_video_fps(pFormatCtx->streams[i]->nb_frames,
538 pFormatCtx->streams[i]->duration,
539 pFormatCtx->streams[i]->time_base,
542 if (videoStream->framePerSec == 0) {
543 if ((int)av_q2d(pFormatCtx->streams[i]->avg_frame_rate) != 0)
544 videoStream->framePerSec = av_q2d(pFormatCtx->streams[i]->avg_frame_rate);
546 videoStream->framePerSec = av_q2d(pFormatCtx->streams[i]->r_frame_rate);
549 videoStream->width = pVideoCodecCtx->width;
550 videoStream->height = pVideoCodecCtx->height;
551 videoStream->bitRate = pVideoCodecCtx->bit_rate;
553 } else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && formatContext->audioStreamId == -1) {
554 audioStream = g_new0(MMFileFormatStream, 1);
556 audioStream->streamType = MMFILE_AUDIO_STREAM;
557 formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
558 formatContext->nbStreams += 1;
559 formatContext->audioStreamId = i;
560 formatContext->audioTotalTrackNum += 1;
562 pAudioCodecCtx = pFormatCtx->streams[i]->codecpar;
563 if (pAudioCodecCtx) {
564 audioStream->codecId = __convert_audio_codec_type(pAudioCodecCtx->codec_id);
565 audioStream->bitRate = pAudioCodecCtx->bit_rate;
566 audioStream->nbChannel = pAudioCodecCtx->channels;
567 audioStream->samplePerSec = pAudioCodecCtx->sample_rate;
568 audioStream->bitPerSample = pAudioCodecCtx->bits_per_coded_sample;
569 audioStream->is_uhqa = __check_uhqa(audioStream->samplePerSec, pFormatCtx->streams[i]->codecpar->format);
574 if (formatContext->nbStreams == 0) {
575 debug_error(DEBUG, "error: there is no audio and video track");
579 #ifdef __MMFILE_TEST_MODE__
580 mmfile_format_print_contents(formatContext);
583 return MMFILE_FORMAT_SUCCESS;
586 mmfile_free(videoStream);
587 mmfile_free(audioStream);
589 formatContext->streams[MMFILE_VIDEO_STREAM] = NULL;
590 formatContext->streams[MMFILE_AUDIO_STREAM] = NULL;
593 avformat_close_input(&pFormatCtx);
594 formatContext->privateFormatData = NULL;
597 formatContext->audioTotalTrackNum = 0;
598 formatContext->videoTotalTrackNum = 0;
599 formatContext->nbStreams = 0;
601 return MMFILE_FORMAT_FAIL;
604 #define DATA_LENGTH 4
606 static void __fill_picture_in_context(char *value, MMFileFormatContext *formatContext)
609 guchar *meta_data = NULL;
610 int current_pos = DATA_LENGTH;
611 unsigned char current_data[DATA_LENGTH] = {0, };
613 meta_data = g_base64_decode(value, &len);
615 debug_log(RELEASE, "no picture");
620 memcpy(current_data, meta_data + current_pos, DATA_LENGTH);
621 len = MMFILE_CONVERT_INT(current_data);
623 current_pos += DATA_LENGTH;
624 mmfile_free(formatContext->artworkMime);
625 formatContext->artworkMime = g_strndup((const char *)meta_data + current_pos, len);
627 /* get description */
629 memcpy(current_data, meta_data + current_pos, DATA_LENGTH);
630 len = MMFILE_CONVERT_INT(current_data);
632 /* get picture data */
633 current_pos += len + (DATA_LENGTH * 5);
634 memcpy(current_data, meta_data + current_pos, DATA_LENGTH);
635 len = MMFILE_CONVERT_INT(current_data);
637 formatContext->artworkSize = len;
639 current_pos += DATA_LENGTH;
640 mmfile_free(formatContext->artwork);
641 formatContext->artwork = g_memdup2(meta_data + current_pos, formatContext->artworkSize);
645 static void __fill_artwork_in_context(AVStream *st, MMFileFormatContext *formatContext)
647 AVPacket pkt = st->attached_pic;
648 int codec_id = st->codecpar->codec_id;
650 if (!pkt.data || pkt.size <= 0)
654 mmfile_free(formatContext->artworkMime);
656 if (codec_id == AV_CODEC_ID_MJPEG)
657 formatContext->artworkMime = g_strdup("image/jpeg");
658 else if (codec_id == AV_CODEC_ID_PNG)
659 formatContext->artworkMime = g_strdup("image/png");
660 else if (codec_id == AV_CODEC_ID_BMP)
661 formatContext->artworkMime = g_strdup("image/bmp");
663 debug_error(DEBUG, "Unknown cover type: 0x%x", codec_id);
666 mmfile_free(formatContext->artwork);
668 formatContext->artworkSize = pkt.size;
669 formatContext->artwork = g_memdup2(pkt.data, pkt.size);
672 static void __fill_metainfo_in_context(AVDictionary *metainfo, MMFileFormatContext *formatContext)
674 AVDictionaryEntry *tag = NULL;
676 while ((tag = av_dict_get(metainfo, "", tag, AV_DICT_IGNORE_SUFFIX))) {
680 if (!g_ascii_strcasecmp(tag->key, "title")) {
681 mmfile_free(formatContext->title);
682 formatContext->title = g_strdup(tag->value);
683 } else if (!g_ascii_strcasecmp(tag->key, "artist")) {
684 mmfile_free(formatContext->artist);
685 formatContext->artist = g_strdup(tag->value);
686 } else if (!g_ascii_strcasecmp(tag->key, "composer")) {
687 mmfile_free(formatContext->composer);
688 formatContext->composer = g_strdup(tag->value);
689 } else if (!g_ascii_strcasecmp(tag->key, "album")) {
690 mmfile_free(formatContext->album);
691 formatContext->album = g_strdup(tag->value);
692 } else if (!g_ascii_strcasecmp(tag->key, "album_artist")) {
693 mmfile_free(formatContext->album_artist);
694 formatContext->album_artist = g_strdup(tag->value);
695 } else if (!g_ascii_strcasecmp(tag->key, "copyright")) {
696 mmfile_free(formatContext->copyright);
697 formatContext->copyright = g_strdup(tag->value);
698 } else if (!g_ascii_strcasecmp(tag->key, "comment")) {
699 mmfile_free(formatContext->comment);
700 formatContext->comment = g_strdup(tag->value);
701 } else if (!g_ascii_strcasecmp(tag->key, "description")) {
702 mmfile_free(formatContext->description);
703 formatContext->description = g_strdup(tag->value);
704 } else if (!g_ascii_strcasecmp(tag->key, "genre")) {
705 mmfile_free(formatContext->genre);
706 formatContext->genre = g_strdup(tag->value);
707 } else if (!g_ascii_strcasecmp(tag->key, "date")) {
708 mmfile_free(formatContext->year);
709 formatContext->year = g_strdup(tag->value);
710 } else if (!g_ascii_strcasecmp(tag->key, "creation_time")) {
711 mmfile_free(formatContext->recDate);
712 formatContext->recDate = g_strdup(tag->value);
713 } else if ((!g_ascii_strcasecmp(tag->key, "track")) || (!g_ascii_strcasecmp(tag->key, "tracknumber"))) {
714 mmfile_free(formatContext->tagTrackNum);
715 formatContext->tagTrackNum = g_strdup(tag->value);
716 } else if (!g_ascii_strcasecmp(tag->key, "lyrics")) {
717 mmfile_free(formatContext->unsyncLyrics);
718 formatContext->unsyncLyrics = g_strdup(tag->value);
719 } else if (!g_ascii_strcasecmp(tag->key, "rotate")) { /*can be "90", "180", "270" */
720 mmfile_free(formatContext->rotate);
721 formatContext->rotate = g_strdup(tag->value);
722 } else if (!g_ascii_strcasecmp(tag->key, "spherical-video")) {
723 ParseSpatialVideoMetadataFromXMLString(tag->value, formatContext);
724 } else if (!g_ascii_strcasecmp(tag->key, "metadata_block_picture")) {
725 __fill_picture_in_context(tag->value, formatContext);
727 debug_log(RELEASE, "Not support metadata. [%s:%s]", tag->key, tag->value);
733 int mmfile_format_read_tag_ffmpg(MMFileFormatContext *formatContext)
735 AVFormatContext *pFormatCtx = NULL;
736 unsigned int idx = 0;
738 mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
739 mm_file_retvm_if_fails(DEBUG, formatContext->privateFormatData, MMFILE_FORMAT_FAIL);
741 if (formatContext->formatType == MM_FILE_FORMAT_3GP || formatContext->formatType == MM_FILE_FORMAT_MP4)
742 MMFileUtilGetMetaDataFromMP4(formatContext);
744 if (formatContext->formatType == MM_FILE_FORMAT_MATROSKA)
745 MMFileUtilGetMetaDataFromMKV(formatContext);
747 pFormatCtx = formatContext->privateFormatData;
749 /*metadata extracted by ffmpeg*/
750 for (idx = 0; idx < pFormatCtx->nb_streams + 1; idx++) {
751 AVDictionary *metainfo = NULL;
754 /* Check metadata of normal stream like audio, video, video cover art
755 * (cover art saved in new stream). refer to mov_read_covr() in ffmpeg.
757 if (idx < pFormatCtx->nb_streams) {
758 st = pFormatCtx->streams[idx];
760 metainfo = st->metadata;
761 } else { /*Check metadata of Content */
762 if (pFormatCtx->metadata != NULL) {
763 metainfo = pFormatCtx->metadata;
769 /*refer to mov_read_covr() in ffmpeg.*/
771 __fill_artwork_in_context(st, formatContext);
774 __fill_metainfo_in_context(metainfo, formatContext);
776 #ifdef __MMFILE_TEST_MODE__
777 mmfile_format_print_tags(formatContext);
781 return MMFILE_FORMAT_SUCCESS;
784 int mmfile_format_read_frame_ffmpg(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
786 AVFormatContext *pFormatCtx = NULL;
787 AVCodecContext *pVideoCodecCtx = NULL;
788 AVCodec *pVideoCodec = NULL;
789 AVCodecParameters *pVideoCodecPar = NULL;
790 AVFrame *pFrame = NULL;
791 struct SwsContext *img_convert_ctx = NULL;
798 mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
799 mm_file_retvm_if_fails(DEBUG, formatContext->privateFormatData, MMFILE_FORMAT_FAIL);
800 mm_file_retvm_if_fails(DEBUG, formatContext->videoTotalTrackNum > 0, MMFILE_FORMAT_FAIL);
801 mm_file_retvm_if_fails(DEBUG, frame, MMFILE_FORMAT_FAIL);
803 pFormatCtx = formatContext->privateFormatData;
805 mm_file_retvm_if_fails(DEBUG, formatContext->videoStreamId != -1, MMFILE_FORMAT_FAIL);
807 pVideoCodecPar = pFormatCtx->streams[formatContext->videoStreamId]->codecpar;
808 mm_file_retvm_if_fails(DEBUG, pVideoCodecPar, MMFILE_FORMAT_FAIL);
810 pVideoCodec = avcodec_find_decoder(pVideoCodecPar->codec_id);
811 mm_file_retvm_if_fails(DEBUG, pVideoCodec, MMFILE_FORMAT_FAIL);
813 pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec);
814 mm_file_retvm_if_fails(DEBUG, pVideoCodecCtx, MMFILE_FORMAT_FAIL);
816 if (avcodec_parameters_to_context(pVideoCodecCtx, pVideoCodecPar) < 0) {
817 debug_error(DEBUG, "error: avcodec_parameters_to_context");
818 avcodec_free_context(&pVideoCodecCtx);
819 return MMFILE_FORMAT_FAIL;
822 debug_msg(RELEASE, "flag: 0x%08X", pVideoCodec->capabilities);
823 /* debug_msg(RELEASE, " DRAW_HORIZ_BAND : %d", pVideoCodec->capabilities & CODEC_CAP_DRAW_HORIZ_BAND ? 1 : 0); */
824 /* debug_msg(RELEASE, " DR1 : %d", pVideoCodec->capabilities & CODEC_CAP_DR1 ? 1 : 0); */
825 /* debug_msg(RELEASE, " PARSE_ONLY : %d", pVideoCodec->capabilities & CODEC_CAP_PARSE_ONLY ? 1 : 0); */
826 /* debug_msg(RELEASE, " TRUNCATED : %d", pVideoCodec->capabilities & CODEC_CAP_TRUNCATED ? 1 : 0); */
827 /* debug_msg(RELEASE, " HWACCEL : %d", pVideoCodec->capabilities & CODEC_CAP_HWACCEL ? 1 : 0); */
828 /* debug_msg(RELEASE, " DELAY : %d", pVideoCodec->capabilities & CODEC_CAP_DELAY ? 1 : 0); */
829 /* debug_msg(RELEASE, " SMALL_LAST_FRAME: %d", pVideoCodec->capabilities & CODEC_CAP_SMALL_LAST_FRAME ? 1 : 0); */
830 /* debug_msg(RELEASE, " HWACCEL_VDPAU : %d", pVideoCodec->capabilities & CODEC_CAP_HWACCEL_VDPAU ? 1 : 0); */
832 if (pVideoCodec->capabilities & AV_CODEC_CAP_TRUNCATED)
833 pVideoCodecCtx->flags |= AV_CODEC_FLAG_TRUNCATED;
835 /*set workaround bug flag*/
836 pVideoCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
838 /* this is solution for PLM issue P13091703323 */
839 /* If using thread when decoding frame, the result of decoding is not always same.
840 Thumbnail of video content is different with original file when copying file. */
841 pVideoCodecCtx->thread_type = 0;
842 pVideoCodecCtx->thread_count = 0;
843 if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) {
844 debug_error(DEBUG, "error: avcodec_open fail.");
845 return MMFILE_FORMAT_FAIL;
848 /* search & decode */
849 ret = _get_first_good_video_frame(pFormatCtx, pVideoCodecCtx, &pFrame, formatContext->cdis);
850 if (ret != MMFILE_FORMAT_SUCCESS) {
851 debug_error(DEBUG, "error: get key frame");
855 debug_msg(RELEASE, "Video default resolution = [%dx%d]", pVideoCodecCtx->coded_width, pVideoCodecCtx->coded_height);
856 debug_msg(RELEASE, "Video coded resolution = [%dx%d]", pVideoCodecCtx->width, pVideoCodecCtx->height);
858 if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
859 width = pVideoCodecCtx->coded_width;
860 height = pVideoCodecCtx->coded_height;
862 width = pVideoCodecCtx->width;
863 height = pVideoCodecCtx->height;
866 numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, width, height, 1);
868 debug_error(DEBUG, "error: av_image_get_buffer_size. [%d x %d]", width, height);
872 frame->frameData = av_malloc(numBytes);
873 if (!frame->frameData) {
874 debug_error(DEBUG, "error: av_malloc.");
878 uint8_t *dst_data[4];
881 ret = av_image_fill_arrays(dst_data, dst_linesize, frame->frameData, AV_PIX_FMT_RGB24, width, height, 1);
883 debug_error(DEBUG, "error: av_image_fill_arrays fail. errcode = 0x%08X", ret);
887 img_convert_ctx = sws_getContext(width, height, pVideoCodecCtx->pix_fmt, width, height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
889 if (NULL == img_convert_ctx) {
890 debug_error(DEBUG, "failed to get img convert ctx");
894 ret = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize, 0, height, dst_data, dst_linesize);
896 debug_error(DEBUG, "failed to convert image");
897 sws_freeContext(img_convert_ctx);
898 img_convert_ctx = NULL;
902 sws_freeContext(img_convert_ctx);
903 img_convert_ctx = NULL;
905 frame->frameSize = numBytes;
906 frame->frameWidth = width;
907 frame->frameHeight = height;
908 frame->configLenth = 0;
909 frame->frameDataFree = av_free;
912 av_frame_free(&pFrame);
914 avcodec_free_context(&pVideoCodecCtx);
916 return MMFILE_FORMAT_SUCCESS;
919 avcodec_free_context(&pVideoCodecCtx);
920 av_freep(&frame->frameData);
921 av_frame_free(&pFrame);
923 return MMFILE_FORMAT_FAIL;
928 int mmfile_format_close_ffmpg(MMFileFormatContext *formatContext)
931 AVFormatContext *pFormatCtx = formatContext->privateFormatData;
934 avformat_close_input(&pFormatCtx);
935 formatContext->privateFormatData = NULL;
939 return MMFILE_FORMAT_SUCCESS;
943 * return average of difference
945 static unsigned int _diff_memory(const void *s1, const void *s2, unsigned int n)
947 char *s = (char *)s1;
948 char *d = (char *)s2;
950 unsigned int ret = 0;
953 for (i = 0, ret = 0; i < n; i++) {
956 ret += (tmp < 0 ? -tmp : tmp);
967 * compare with center line.
969 static bool __is_good_pgm(unsigned char *buf, int wrap, int xsize, int ysize)
971 #define _MM_CHUNK_NUM 8 /*FIXME*/
972 #define _MM_CHUNK_LIMIT (_MM_CHUNK_NUM / 2)
973 #define _MM_CHUNK_DIFF_LIMIT (_MM_CHUNK_LIMIT * 2 + 1) /*FIXME*/
978 unsigned char *cnt; /*center line of image*/
980 unsigned int sum_diff;
984 step = ysize / _MM_CHUNK_NUM;
985 cnt_offset = (ysize / 2);
986 cnt = buf + cnt_offset * wrap;
988 debug_msg(RELEASE, "checking frame. %p, %d, %d, %d", buf, wrap, xsize, ysize);
990 /*if too small, always ok return.*/
991 if (ysize < _MM_CHUNK_NUM)
994 for (point = 0, sum_diff = 0, i = step; i < ysize; i += step) {
999 is_different = _diff_memory(cnt, buf + i * wrap, xsize);
1000 point += (is_different == 0 ? 0 : 1);
1001 sum_diff += is_different;
1003 debug_msg(RELEASE, "check %04d line. %s [%d]", i, (is_different == 0 ? "same" : "different"), is_different);
1005 if (point < _MM_CHUNK_LIMIT)
1008 if (sum_diff <= _MM_CHUNK_DIFF_LIMIT) {
1009 debug_msg(RELEASE, "Bad :-(");
1013 debug_msg(RELEASE, "Good :-)");
1020 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1021 static void _save_pgm(unsigned char *buf, int wrap, int xsize, int ysize, char *filename)
1026 f = fopen(filename, "w");
1028 fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
1029 for (i = 0; i < ysize; i++)
1030 fwrite(buf + i * wrap, 1, xsize, f);
1036 static int _get_first_good_video_frame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, AVFrame **pFrame, int cdis)
1038 #define _RETRY_SEARCH_LIMIT 250
1039 #define _KEY_SEARCH_LIMIT (_RETRY_SEARCH_LIMIT*2) /*2 = 1 read. some frame need to read one more*/
1040 #define _FRAME_SEARCH_LIMIT 500
1042 #define _RETRY_SEARCH_LIMIT_CDIS 10
1043 #define _KEY_SEARCH_LIMIT_CDIS (_RETRY_SEARCH_LIMIT*2) /*2 = 1 read. some frame need to read one more*/
1044 #define _FRAME_SEARCH_LIMIT_CDIS 10
1046 AVPacket *pkt = NULL;
1048 AVFrame *frame = NULL;
1049 AVFrame *tmp_frame = NULL;
1050 AVFrame *first_frame = NULL;
1057 bool key_detected = false;
1058 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1059 char pgm_name[256] = {0, };
1061 int key_search_limit = (cdis == 1) ? _KEY_SEARCH_LIMIT_CDIS : _KEY_SEARCH_LIMIT;
1062 int frame_search_limit = (cdis == 1) ? _FRAME_SEARCH_LIMIT_CDIS : _FRAME_SEARCH_LIMIT;
1064 first_frame = av_frame_alloc();
1065 tmp_frame = av_frame_alloc();
1067 if (!first_frame || !tmp_frame) {
1068 debug_error(DEBUG, "failed to alloc frame.");
1069 av_frame_free(&first_frame);
1070 av_frame_free(&tmp_frame);
1072 return MMFILE_FORMAT_FAIL;
1075 debug_msg(RELEASE, "frame: 1. %p, 2. %p", first_frame, tmp_frame);
1077 pCodecCtx->skip_frame = AVDISCARD_BIDIR;
1078 frame = first_frame;
1080 while (i < key_search_limit && v < frame_search_limit) {
1081 pkt = av_packet_alloc();
1083 debug_error(DEBUG, "packet allocation failed.");
1087 if (av_read_frame(pFormatCtx, pkt) < 0) {
1088 debug_error(DEBUG, "read failed. (maybe EOF or broken)");
1092 if (avcodec_get_type(pFormatCtx->streams[pkt->stream_index]->codecpar->codec_id) != AVMEDIA_TYPE_VIDEO)
1096 if (!(pkt->flags & AV_PKT_FLAG_KEY) && !key_detected)
1099 #ifdef __MMFILE_TEST_MODE__
1100 _dump_av_packet(pkt);
1103 key_detected = false;
1104 debug_msg(RELEASE, "video frame: %d, %d, %d", retry, i, v);
1106 ret = avcodec_send_packet(pCodecCtx, pkt);
1107 if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
1108 debug_error(RELEASE, "Error while avcodec_send_packet[%2d]", ret);
1112 ret = avcodec_receive_frame(pCodecCtx, frame);
1114 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
1115 debug_msg(RELEASE, "decode not completed.");
1116 key_detected = true;
1119 debug_warning(DEBUG, "Error while decoding frame %dth", i);
1123 if (!frame->key_frame) {
1124 debug_msg(RELEASE, "skip (not key frame).");
1125 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1126 memset(pgm_name, 0x00, sizeof(pgm_name));
1127 snprintf(pgm_name, sizeof(pgm_name), "./not_key_%d_%d_%d.pgm", retry, i, v);
1128 _save_pgm(frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height, pgm_name);
1133 debug_msg(RELEASE, "key frame!");
1134 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1135 memset(pgm_name, 0x00, sizeof(pgm_name));
1136 snprintf(pgm_name, sizeof(pgm_name), "./key_%d_%d_%d.pgm", retry, i, v);
1137 _save_pgm(frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height, pgm_name);
1141 if (__is_good_pgm(frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height)) {
1142 debug_msg(RELEASE, "is good frame.");
1146 debug_warning(RELEASE, "not good fame. retry scanning.");
1151 /*set buffer frame*/
1154 if (retry > _RETRY_SEARCH_LIMIT)
1157 av_packet_free(&pkt);
1160 /*free pkt after loop breaking*/
1161 av_packet_free(&pkt);
1163 debug_msg(RELEASE, "found: %d, retry: %d", found, retry);
1165 /*set decode frame to output*/
1167 if (retry == 0 || found == retry) {
1168 *pFrame = first_frame;
1169 av_frame_free(&tmp_frame);
1171 *pFrame = tmp_frame;
1172 av_frame_free(&first_frame);
1175 av_frame_free(&first_frame);
1176 av_frame_free(&tmp_frame);
1179 debug_msg(RELEASE, "out frame: %p", *pFrame);
1181 pCodecCtx->skip_frame = AVDISCARD_NONE;
1183 return (found > 0) ? MMFILE_FORMAT_SUCCESS : MMFILE_FORMAT_FAIL;