Support m360 tag in mp4
[platform/core/multimedia/libmm-fileinfo.git] / formats / ffmpeg / mm_file_format_ffmpeg.c
1 /*
2  * libmm-fileinfo
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Haejeong Kim <backto.kim@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include <libavformat/avformat.h>
26 #include <libavcodec/avcodec.h>
27 #include <libavutil/imgutils.h>
28 #include <libavutil/display.h>
29 #include <libswscale/swscale.h>
30 #include <mm_error.h>
31 #include <mm_types.h>
32 #include "mm_file_debug.h"
33 #include "mm_file_formats.h"
34 #include "mm_file_utils.h"
35 #include "mm_file_format_ffmpeg.h"
36
37 static int g_max_analyze_duration = 0;
38 static int g_probesize = 0;
39
40 #ifdef __MMFILE_TEST_MODE__
41 static void _dump_av_packet(AVPacket *pkt)
42 {
43         debug_msg(RELEASE, "--------- AV Packet -----------");
44         debug_msg(RELEASE, " pts: %lld", pkt->pts);
45         debug_msg(RELEASE, " dts: %lld", pkt->dts);
46         debug_msg(RELEASE, " data: %p", pkt->data);
47         debug_msg(RELEASE, " size: %d", pkt->size);
48         debug_msg(RELEASE, " stream_index: %d", pkt->stream_index);
49         debug_msg(RELEASE, " flags: 0x%08X, %s", pkt->flags, (pkt->flags & AV_PKT_FLAG_KEY) ? "Keyframe" : "_");
50         debug_msg(RELEASE, " duration: %lld", pkt->duration);
51         /*debug_msg(RELEASE, " destruct: %p", pkt->destruct);*/
52         /*debug_msg(RELEASE, " priv: %p", pkt->priv);*/
53         debug_msg(RELEASE, " pos: %lld", pkt->pos);
54         debug_msg(RELEASE, "-------------------------------");
55 }
56 #endif
57
58 static int _get_first_good_video_frame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, AVFrame **pFrame, int cdis, int videoStreamId);
59
60 static int __convert_vidio_codec_type(int AVVideoCodecID)
61 {
62         switch (AVVideoCodecID) {
63         case AV_CODEC_ID_MPEG1VIDEO:
64                 return MM_VIDEO_CODEC_MPEG1;
65         case AV_CODEC_ID_MPEG2VIDEO:  /*/< preferred ID for MPEG-1/2 video decoding */
66         case AV_CODEC_ID_MPEG2TS:
67                 return MM_VIDEO_CODEC_MPEG2;
68         case AV_CODEC_ID_H261:
69                 return MM_VIDEO_CODEC_H261;
70         case AV_CODEC_ID_H263:
71                 return MM_VIDEO_CODEC_H263;
72         case AV_CODEC_ID_MPEG4:
73         case AV_CODEC_ID_MSMPEG4V1:
74         case AV_CODEC_ID_MSMPEG4V2:
75         case AV_CODEC_ID_MSMPEG4V3:
76                 return MM_VIDEO_CODEC_MPEG4;
77         case AV_CODEC_ID_WMV1:
78         case AV_CODEC_ID_WMV2:
79                 return MM_VIDEO_CODEC_WMV;
80         case AV_CODEC_ID_H263P:
81         case AV_CODEC_ID_H263I:
82                 return MM_VIDEO_CODEC_H263;
83         case AV_CODEC_ID_FLV1:
84                 return MM_VIDEO_CODEC_FLV;
85         case AV_CODEC_ID_H264:
86                 return MM_VIDEO_CODEC_H264;
87         case AV_CODEC_ID_INDEO2:
88         case AV_CODEC_ID_INDEO3:
89         case AV_CODEC_ID_INDEO4:
90         case AV_CODEC_ID_INDEO5:
91                 return MM_VIDEO_CODEC_INDEO;
92         case AV_CODEC_ID_THEORA:
93                 return MM_VIDEO_CODEC_THEORA;
94         case AV_CODEC_ID_CINEPAK:
95                 return MM_VIDEO_CODEC_CINEPAK;
96         case AV_CODEC_ID_VC1:
97                 return MM_VIDEO_CODEC_VC1;
98         case AV_CODEC_ID_WMV3:
99                 return MM_VIDEO_CODEC_WMV;
100         case AV_CODEC_ID_AVS:
101                 return MM_VIDEO_CODEC_AVS;
102         case AV_CODEC_ID_RL2:
103         case AV_CODEC_ID_RV10:  /* RealVideo 1 */
104         case AV_CODEC_ID_RV20:  /* RealVideo 2 */
105         case AV_CODEC_ID_RV30:  /* RealVideo 3 */
106         case AV_CODEC_ID_RV40:  /* RealVideo 4 */
107                 return MM_VIDEO_CODEC_REAL;
108         case AV_CODEC_ID_AV1:   /* AOMedia Video 1 */
109                 return MM_VIDEO_CODEC_AV1;
110         case AV_CODEC_ID_HEVC:
111                 return MM_VIDEO_CODEC_MPEG4;
112 #ifdef USE_CODEC_VPX
113         case AV_CODEC_ID_VP8:
114                 return MM_VIDEO_CODEC_VP8;
115         case AV_CODEC_ID_VP9:
116                 return MM_VIDEO_CODEC_VP9;
117 #endif
118         default:
119                 return MM_VIDEO_CODEC_NONE;
120         }
121 }
122
123 static int __convert_audio_codec_type(int AVAudioCodecID)
124 {
125         switch (AVAudioCodecID) {
126         case AV_CODEC_ID_AMR_NB:
127         case AV_CODEC_ID_AMR_WB:
128                 return MM_AUDIO_CODEC_AMR;
129         /* RealAudio codecs*/
130         case AV_CODEC_ID_RA_144:        /* RealAudio 1 */
131         case AV_CODEC_ID_RA_288:        /* RealAudio 2 */
132         case AV_CODEC_ID_COOK:          /* RealAudio 6 */
133                 return MM_AUDIO_CODEC_REAL;
134         case AV_CODEC_ID_MP2:
135                 return MM_AUDIO_CODEC_MP2;
136         case AV_CODEC_ID_MP3:
137         case AV_CODEC_ID_MP3ADU:
138         case AV_CODEC_ID_MP3ON4:
139                 return MM_AUDIO_CODEC_MP3;
140         case AV_CODEC_ID_AAC:
141                 return MM_AUDIO_CODEC_AAC;
142         case AV_CODEC_ID_AC3:
143                 return MM_AUDIO_CODEC_AC3;
144         case AV_CODEC_ID_VORBIS:
145                 return MM_AUDIO_CODEC_VORBIS;
146         case AV_CODEC_ID_WMAV1:
147         case AV_CODEC_ID_WMAV2:
148         case AV_CODEC_ID_WMAVOICE:
149         case AV_CODEC_ID_WMAPRO:
150         case AV_CODEC_ID_WMALOSSLESS:
151                 return MM_AUDIO_CODEC_WMA;
152         case AV_CODEC_ID_FLAC:
153                 return MM_AUDIO_CODEC_FLAC;
154         case AV_CODEC_ID_ALAC:
155                 return MM_AUDIO_CODEC_ALAC;
156         case AV_CODEC_ID_WAVPACK:
157                 return MM_AUDIO_CODEC_WAVE;
158         case AV_CODEC_ID_ATRAC3:
159         case AV_CODEC_ID_ATRAC3P:
160         case AV_CODEC_ID_EAC3:
161                 return MM_AUDIO_CODEC_AC3;
162         case AV_CODEC_ID_PCM_S8:
163         case AV_CODEC_ID_PCM_S16BE:
164         case AV_CODEC_ID_PCM_S24BE:
165         case AV_CODEC_ID_PCM_S32BE:
166                 return MM_AUDIO_CODEC_PCM;
167         default:
168                 return MM_AUDIO_CODEC_NONE;
169         }
170 }
171
172 /* plugin manadatory API */
173 int mmfile_format_read_stream_ffmpg(MMFileFormatContext *formatContext);
174 int mmfile_format_read_frame_ffmpg(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
175 int mmfile_format_read_tag_ffmpg(MMFileFormatContext *formatContext);
176 int mmfile_format_close_ffmpg(MMFileFormatContext *formatContext);
177
178 static void __count_stream_num(AVFormatContext *pFormatCtx, MMFileFormatContext *formatContext)
179 {
180         unsigned int i = 0;
181
182         formatContext->videoTotalTrackNum = 0;
183         formatContext->audioTotalTrackNum = 0;
184
185         for (i = 0; i < pFormatCtx->nb_streams; i++) {
186                 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
187                         debug_msg(RELEASE, "FFMPEG video codec id: 0x%08X", pFormatCtx->streams[i]->codecpar->codec_id);
188
189                         AVPacket pkt = pFormatCtx->streams[i]->attached_pic;
190                         if ((pkt.data != NULL) && (pkt.size > 0))
191                                 continue;
192
193                         /*eventhough codec_id is 0, avformat_find_stream_info() can find proper codec_id. */
194                         formatContext->videoTotalTrackNum += 1;
195                 }
196                 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
197                         debug_msg(RELEASE, "FFMPEG audio codec id: 0x%08X", pFormatCtx->streams[i]->codecpar->codec_id);
198                         formatContext->audioTotalTrackNum += 1;
199                 }
200         }
201 }
202
203 static bool __mmf_mem_open(MMFmemIOHandle **handle, const char *filename)
204 {
205         MMFmemIOHandle *memHandle = NULL;
206         char **splitedString = NULL;
207
208         filename += strlen(MMFILE_MEM_URI);
209         splitedString = g_strsplit(filename, ":", -1);
210
211         if (g_strv_length(splitedString) < 2) {
212                 debug_error(DEBUG, "invalid param");
213                 g_strfreev(splitedString);
214
215                 return false;
216         }
217
218         memHandle = g_new0(MMFmemIOHandle, 1);
219
220         /*memory allocation address changed. memHandle->ptr = (unsigned char*)atoi(splitedString[0]); */
221         memHandle->ptr = (unsigned char *)atoll(splitedString[0]);
222         memHandle->size = atoi(splitedString[1]);
223         memHandle->offset = 0;
224         memHandle->state = 0;
225
226         *handle = memHandle;
227
228         g_strfreev(splitedString);
229
230         return true;
231 }
232
233 static int __mmf_mem_read(void *opaque, uint8_t *buf, int size)
234 {
235         MMFmemIOHandle *memHandle = NULL;
236         const unsigned char *c = NULL;
237         int len = 0;
238
239         mm_file_retvm_if_fails(DEBUG, opaque, MMFILE_UTIL_FAIL);
240         mm_file_retvm_if_fails(DEBUG, buf, MMFILE_UTIL_FAIL);
241
242         memHandle = opaque;
243
244         mm_file_retvm_if_fails(DEBUG, memHandle->ptr, MMFILE_UTIL_FAIL);
245         mm_file_retvm_if_fails(DEBUG, memHandle->offset < memHandle->size, MMFILE_UTIL_FAIL);
246
247         c = memHandle->ptr + memHandle->offset;
248
249         if (memHandle->state != EOF) {
250                 len = size;
251                 if (len + memHandle->offset > memHandle->size)
252                         len = memHandle->size - memHandle->offset;
253         }
254
255         memcpy(buf, c, len);
256         memHandle->offset += len;
257
258         if (memHandle->offset == memHandle->size)
259                 memHandle->state = EOF;
260
261         return len;
262 }
263
264 static int64_t __mmf_mem_seek(void *opaque, int64_t pos, int whence)
265 {
266         MMFmemIOHandle *memHandle = NULL;
267         long long tmp_offset = 0;
268
269         mm_file_retvm_if_fails(DEBUG, opaque, MMFILE_UTIL_FAIL);
270
271         memHandle = opaque;
272
273         switch (whence) {
274         case SEEK_SET:
275                 tmp_offset = 0 + pos;
276                 break;
277         case SEEK_CUR:
278                 tmp_offset = memHandle->offset + pos;
279                 break;
280         case SEEK_END:
281                 tmp_offset = memHandle->size + pos;
282                 break;
283         case AVSEEK_SIZE:       /*FFMPEG specific*/
284                 return memHandle->size;
285         default:
286                 return MMFILE_UTIL_FAIL;
287         }
288
289         /*check validation*/
290         mm_file_retvm_if_fails(DEBUG, tmp_offset >= 0 && tmp_offset <= memHandle->size, MMFILE_UTIL_FAIL);
291
292         /*set */
293         memHandle->state = (tmp_offset >= memHandle->size) ? EOF : !EOF;
294         memHandle->offset = (unsigned int) tmp_offset;
295
296         return tmp_offset;
297 }
298
299
300 int mmfile_format_open_ffmpg(MMFileFormatContext *formatContext)
301 {
302         AVFormatContext *pFormatCtx = NULL;
303         const AVInputFormat *grab_iformat = NULL;
304         char ffmpegFormatName[MMFILE_FILE_FMT_MAX_LEN] = {0, };
305         AVIOContext *pIOCtx = NULL;
306         MMFmemIOHandle *handle = NULL;
307         uint8_t *avio_ctx_buffer = NULL;
308
309         formatContext->ReadStream   = mmfile_format_read_stream_ffmpg;
310         formatContext->ReadFrame    = mmfile_format_read_frame_ffmpg;
311         formatContext->ReadTag      = mmfile_format_read_tag_ffmpg;
312         formatContext->Close        = mmfile_format_close_ffmpg;
313
314         debug_msg(RELEASE, "ffmpeg version: %d", avformat_version());
315         /**
316          * FFMPEG DEBUG LEVEL
317          *  AV_LOG_QUIET -1
318          *  AV_LOG_FATAL 0
319          *  AV_LOG_ERROR 0
320          *  AV_LOG_WARNING 1
321          *  AV_LOG_INFO 1
322          *  AV_LOG_VERBOSE 1
323          *  AV_LOG_DEBUG 2
324          */
325 #ifdef __MMFILE_TEST_MODE__
326         av_log_set_level(AV_LOG_TRACE);
327 #else
328         av_log_set_level(AV_LOG_QUIET);
329 #endif
330
331         if (formatContext->filesrc->type  == MM_FILE_SRC_TYPE_MEMORY) {
332                 if (mmfile_util_get_ffmpeg_format(formatContext->filesrc->memory.format, ffmpegFormatName) != MMFILE_UTIL_SUCCESS) {
333                         debug_error(DEBUG, "error: mmfile_util_get_ffmpeg_format");
334                         return MMFILE_FORMAT_FAIL;
335                 }
336
337                 grab_iformat = av_find_input_format(ffmpegFormatName);
338                 mm_file_retvm_if_fails(DEBUG, grab_iformat, MMFILE_UTIL_FAIL);
339
340                 avio_ctx_buffer = av_malloc(MMFILE_AVIO_BUFFER_LEN);
341                 mm_file_retvm_if_fails(DEBUG, avio_ctx_buffer, MMFILE_UTIL_FAIL);
342
343                 if (!__mmf_mem_open(&handle, formatContext->uriFileName)) {
344                         debug_error(DEBUG, "failed to _mmf_mem_open.");
345                         goto exception;
346                 }
347
348                 pIOCtx = avio_alloc_context(avio_ctx_buffer, MMFILE_AVIO_BUFFER_LEN, 0, handle, __mmf_mem_read, NULL, __mmf_mem_seek);
349                 if (!pIOCtx) {
350                         debug_error(DEBUG, "error: cannot alloc io context");
351                         goto exception;
352                 }
353
354                 pFormatCtx = avformat_alloc_context();
355                 if (!pFormatCtx) {
356                         debug_error(DEBUG, "failed to avformat_alloc_context");
357                         goto exception;
358                 }
359
360                 pFormatCtx->pb = pIOCtx;
361
362                 if (avformat_open_input(&pFormatCtx, "", grab_iformat, NULL) < 0) {
363                         debug_error(DEBUG, "error: cannot open %s", formatContext->uriFileName);
364                         goto exception;
365                 }
366
367                 formatContext->privateFormatData = pFormatCtx;
368         }
369
370         if (formatContext->filesrc->type  == MM_FILE_SRC_TYPE_FILE) {
371                 if (avformat_open_input(&pFormatCtx, formatContext->filesrc->file.path, NULL, NULL) < 0) {
372                         debug_error(DEBUG, "error: cannot open %s", formatContext->filesrc->file.path);
373                         goto exception;
374                 }
375
376                 formatContext->privateFormatData = pFormatCtx;
377         }
378
379         if (!pFormatCtx) {
380                 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.");
381                 goto exception;
382         }
383
384         debug_msg(RELEASE, "number of stream: %d", pFormatCtx->nb_streams);
385
386         __count_stream_num(pFormatCtx, formatContext);
387
388         debug_msg(RELEASE, "format: %s (%s)", pFormatCtx->iformat->name, pFormatCtx->iformat->long_name);
389 #ifdef __MMFILE_TEST_MODE__
390         av_dump_format(pFormatCtx, 0, formatContext->filesrc->file.path, 0);
391 #endif
392
393         return MMFILE_FORMAT_SUCCESS;
394
395 exception: /* fail to get content information */
396         if (formatContext->filesrc->type  == MM_FILE_SRC_TYPE_MEMORY) {
397                 if (avio_ctx_buffer)
398                         av_free(avio_ctx_buffer);
399
400                 mmfile_free(handle);
401
402                 if (pIOCtx)
403                         av_free(pIOCtx);
404                 if (pFormatCtx)
405                         avformat_close_input(&pFormatCtx);
406         } else {
407                 mmfile_format_close_ffmpg(formatContext);
408         }
409
410         formatContext->privateFormatData = NULL;
411
412         return MMFILE_FORMAT_FAIL;
413 }
414
415 static int __get_video_fps(int frame_cnt, int duration, AVRational r_frame_rate, int is_roundup)
416 {
417         double fps, round;
418
419         debug_msg(RELEASE, "frame count: %d, dur: %d, num: %d, den: %d", frame_cnt, duration, r_frame_rate.num, r_frame_rate.den);
420
421         if (duration <= 0 || r_frame_rate.num <= 0 || r_frame_rate.den <= 0)
422                 return 0;
423
424         round = (is_roundup != 0 ? 0.50f : 0.00f);
425
426         fps = (double)frame_cnt / ((double)(duration * r_frame_rate.num) / r_frame_rate.den) + round;
427
428         return (int)fps;
429 }
430
431 static bool __check_uhqa(int sample_rate, enum AVSampleFormat sample_fmt_info)
432 {
433         debug_error(RELEASE, "[sample rate %d, sample format %d]", sample_rate, sample_fmt_info);
434
435         if (sample_rate >= 44100 && sample_fmt_info >= AV_SAMPLE_FMT_S32) {
436                 debug_msg(RELEASE, "UHQA CONTENT");
437                 return true;
438         }
439
440         return false;
441 }
442
443 int mmfile_format_read_stream_ffmpg(MMFileFormatContext *formatContext)
444 {
445         AVFormatContext *pFormatCtx = NULL;
446         AVCodecParameters *pAudioCodecCtx = NULL;
447         AVCodecParameters *pVideoCodecCtx = NULL;
448         MMFileFormatStream *videoStream = NULL;
449         MMFileFormatStream *audioStream = NULL;
450         unsigned int i = 0;
451
452         mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
453         mm_file_retvm_if_fails(DEBUG, formatContext->privateFormatData, MMFILE_FORMAT_FAIL);
454
455         pFormatCtx = formatContext->privateFormatData;
456         pFormatCtx->start_time = -1;
457
458         /**
459          * If you could not find codec parameters for stream info,
460          * consider increasing the value for the 'analyzeduration' and 'probesize' options.
461          */
462         /**
463          *@important if data is corrupted, occur segment fault by av_find_stream_info().
464          *                      - fixed 2009-06-25.
465          */
466         /**
467          * fixed 2021-11-09
468          * if the content is 8k, the mem-usage in avformat_find_stream_info() is too large, 300MB or more.
469          * so we adjust 'probesize' to reduce memory usage in avformat_find_stream_info().
470          * Please refer to below for detail.
471          * https://ffmpeg.org/ffmpeg-formats.html#Format-Options
472          */
473         if (g_max_analyze_duration == 0)
474                 g_max_analyze_duration = mmfile_get_int_from_ini(MMFILE_INI_MAXANLDURATION, MMFILE_DEFAULT_MAXANLDURATION);
475         if (g_probesize == 0)
476                 g_probesize = mmfile_get_int_from_ini(MMFILE_INI_PROBESIZE, MMFILE_DEFAULT_PROBESIZE);
477
478         if (formatContext->formatType == MM_FILE_FORMAT_M2TS)
479                 pFormatCtx->max_analyze_duration = g_max_analyze_duration;      // MPEGTS file timeout set
480         else
481                 pFormatCtx->probesize = g_probesize;    // the size of the data(packet) to probe stream information
482
483         debug_msg(RELEASE, "max_analyze_duration: %"PRId64", probesize: %"PRId64"", pFormatCtx->max_analyze_duration, pFormatCtx->probesize);
484
485         if (formatContext->cdis != 1) {
486                 if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
487                         debug_warning(DEBUG, "failed to find stream info");
488                         goto exception;
489                 }
490         }
491
492         debug_msg(RELEASE, "FFMPEG: dur %"PRId64", start %"PRId64"", pFormatCtx->duration, pFormatCtx->start_time);
493
494         /**
495          *@note asf has long duration bug. and Some content's start time is wrong(negative number).
496          * Generally, mpegts has wrong start time(positive large value). So skip start time for mpegts format.
497          */
498         if (pFormatCtx->start_time < 0 || formatContext->formatType == MM_FILE_FORMAT_M2TS) {
499                 debug_warning(DEBUG, "Wrong Start time = %"PRId64"", pFormatCtx->start_time);
500                 formatContext->duration = (long long)(pFormatCtx->duration) * 1000 / AV_TIME_BASE;
501         } else {
502                 formatContext->duration = (long long)(pFormatCtx->duration + pFormatCtx->start_time) * 1000 / AV_TIME_BASE;
503         }
504
505         formatContext->videoStreamId = -1;
506         formatContext->audioStreamId = -1;
507         formatContext->nbStreams = 0;
508         formatContext->videoTotalTrackNum = 0;
509         formatContext->audioTotalTrackNum = 0;
510
511         for (i = 0; i < pFormatCtx->nb_streams; i++) {
512                 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && formatContext->videoStreamId == -1) {
513                         videoStream = g_new0(MMFileFormatStream, 1);
514
515                         videoStream->streamType = MMFILE_VIDEO_STREAM;
516                         formatContext->streams[MMFILE_VIDEO_STREAM] = videoStream;
517                         formatContext->nbStreams += 1;
518                         formatContext->videoStreamId = i;
519                         formatContext->videoTotalTrackNum += 1;
520
521                         pVideoCodecCtx = pFormatCtx->streams[i]->codecpar;
522                         if (pVideoCodecCtx) {
523                                 videoStream->codecId            = __convert_vidio_codec_type(pVideoCodecCtx->codec_id);
524                                 if (videoStream->codecId == MM_VIDEO_CODEC_NONE) {
525                                         debug_error(RELEASE, "Proper codec is not found in [%d] stream", i);
526                                         formatContext->videoStreamId = -1;
527                                         mmfile_free(videoStream);
528                                         formatContext->streams[MMFILE_VIDEO_STREAM] = NULL;
529                                         videoStream = NULL;
530                                         continue;
531                                 }
532
533                                 /**
534                                  * Get FPS
535                                  * 1. try to get average fps of video stream.
536                                  * 2. if (1) failed, try to get fps of media container.
537                                  */
538                                 videoStream->framePerSec        = __get_video_fps(pFormatCtx->streams[i]->nb_frames,
539                                                                                         pFormatCtx->streams[i]->duration,
540                                                                                         pFormatCtx->streams[i]->time_base,
541                                                                                         1);
542
543                                 if (videoStream->framePerSec == 0) {
544                                         if ((int)av_q2d(pFormatCtx->streams[i]->avg_frame_rate) != 0)
545                                                 videoStream->framePerSec = av_q2d(pFormatCtx->streams[i]->avg_frame_rate);
546                                         else
547                                                 videoStream->framePerSec = av_q2d(pFormatCtx->streams[i]->r_frame_rate);
548                                 }
549
550                                 videoStream->width                      = pVideoCodecCtx->width;
551                                 videoStream->height                     = pVideoCodecCtx->height;
552                                 videoStream->bitRate            = pVideoCodecCtx->bit_rate;
553                         }
554                 } else if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && formatContext->audioStreamId == -1) {
555                         audioStream = g_new0(MMFileFormatStream, 1);
556
557                         audioStream->streamType = MMFILE_AUDIO_STREAM;
558                         formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
559                         formatContext->nbStreams += 1;
560                         formatContext->audioStreamId = i;
561                         formatContext->audioTotalTrackNum += 1;
562
563                         pAudioCodecCtx = pFormatCtx->streams[i]->codecpar;
564                         audioStream->codecId            = __convert_audio_codec_type(pAudioCodecCtx->codec_id);
565                         audioStream->bitRate            = pAudioCodecCtx->bit_rate;
566                         audioStream->nbChannel          = pAudioCodecCtx->ch_layout.nb_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);
570                 }
571         }
572
573         if (formatContext->nbStreams == 0) {
574                 debug_error(DEBUG, "error: there is no audio and video track");
575                 goto exception;
576         }
577
578 #ifdef __MMFILE_TEST_MODE__
579         mmfile_format_print_contents(formatContext);
580 #endif
581
582         return MMFILE_FORMAT_SUCCESS;
583
584 exception:
585         mmfile_free(videoStream);
586         mmfile_free(audioStream);
587
588         formatContext->streams[MMFILE_VIDEO_STREAM] = NULL;
589         formatContext->streams[MMFILE_AUDIO_STREAM] = NULL;
590
591         if (pFormatCtx) {
592                 avformat_close_input(&pFormatCtx);
593                 formatContext->privateFormatData = NULL;
594         }
595
596         formatContext->audioTotalTrackNum = 0;
597         formatContext->videoTotalTrackNum = 0;
598         formatContext->nbStreams = 0;
599
600         return MMFILE_FORMAT_FAIL;
601 }
602
603 #define DATA_LENGTH 4
604
605 static void __fill_picture_in_context(char *value, MMFileFormatContext *formatContext)
606 {
607         gsize len = 0;
608         guchar *meta_data = NULL;
609         int current_pos = DATA_LENGTH;
610         unsigned char current_data[DATA_LENGTH] = {0, };
611
612         meta_data = g_base64_decode(value, &len);
613         if (!meta_data) {
614                 debug_msg(RELEASE, "no picture");
615                 return;
616         }
617
618         /* get mime_type */
619         memcpy(current_data, meta_data + current_pos, DATA_LENGTH);
620         len = (unsigned int)MMFILE_CONVERT_INT(current_data);
621
622         current_pos += DATA_LENGTH;
623         mmfile_free(formatContext->artworkMime);
624         formatContext->artworkMime = g_strndup((const char *)meta_data + current_pos, len);
625
626         /* get description */
627         current_pos += len;
628         memcpy(current_data, meta_data + current_pos, DATA_LENGTH);
629         len = (unsigned int)MMFILE_CONVERT_INT(current_data);
630
631         /* get picture data */
632         current_pos += len + (DATA_LENGTH * 5);
633         memcpy(current_data, meta_data + current_pos, DATA_LENGTH);
634         len = (unsigned int)MMFILE_CONVERT_INT(current_data);
635
636         formatContext->artworkSize = len;
637
638         current_pos += DATA_LENGTH;
639         mmfile_free(formatContext->artwork);
640         formatContext->artwork = g_memdup2(meta_data + current_pos, formatContext->artworkSize);
641         g_free(meta_data);
642 }
643
644 static void __fill_artwork_in_context(AVStream *st, MMFileFormatContext *formatContext)
645 {
646         AVPacket pkt = st->attached_pic;
647         int codec_id = st->codecpar->codec_id;
648
649         if (!pkt.data || pkt.size <= 0)
650                 return;
651
652         /*Set mime type*/
653         mmfile_free(formatContext->artworkMime);
654
655         if (codec_id == AV_CODEC_ID_MJPEG)
656                 formatContext->artworkMime = g_strdup("image/jpeg");
657         else if (codec_id == AV_CODEC_ID_PNG)
658                 formatContext->artworkMime = g_strdup("image/png");
659         else if (codec_id == AV_CODEC_ID_BMP)
660                 formatContext->artworkMime = g_strdup("image/bmp");
661         else
662                 debug_error(DEBUG, "Unknown cover type: 0x%x", codec_id);
663
664         /*Copy artwork*/
665         mmfile_free(formatContext->artwork);
666
667         formatContext->artworkSize = pkt.size;
668         formatContext->artwork = g_memdup2(pkt.data, pkt.size);
669 }
670
671 static void __fill_rotate_in_context(AVStream *st, MMFileFormatContext *formatContext)
672 {
673         int i;
674         double rotate = 0.0;
675         bool found = false;
676
677         for (i = 0; i < st->codecpar->nb_coded_side_data; i++) {
678                 const AVPacketSideData *sd = &st->codecpar->coded_side_data[i];
679                 if (sd->type == AV_PKT_DATA_DISPLAYMATRIX) {
680                         found = true;
681                         rotate = av_display_rotation_get((const int32_t *)sd->data);
682                         break;
683                 }
684         }
685
686         if (!found)
687                 return;
688
689         rotate = -rotate;
690         if (rotate < 0) // for backward compatibility
691                 rotate += 360;
692         debug_msg(RELEASE, "Rotate: %f", rotate);
693         mmfile_free(formatContext->rotate);
694         formatContext->rotate = g_strdup_printf("%g", rotate);
695 }
696
697 static void __fill_metainfo_in_context(AVDictionary *metainfo, MMFileFormatContext *formatContext)
698 {
699         AVDictionaryEntry *tag = NULL;
700
701         while ((tag = av_dict_get(metainfo, "", tag, AV_DICT_IGNORE_SUFFIX))) {
702                 if (!tag->key)
703                         continue;
704
705                 if (!g_ascii_strcasecmp(tag->key, "title")) {
706                         mmfile_free(formatContext->title);
707                         formatContext->title = g_strdup(tag->value);
708                 } else if (!g_ascii_strcasecmp(tag->key, "artist")) {
709                         mmfile_free(formatContext->artist);
710                         formatContext->artist = g_strdup(tag->value);
711                 } else if (!g_ascii_strcasecmp(tag->key, "composer")) {
712                         mmfile_free(formatContext->composer);
713                         formatContext->composer = g_strdup(tag->value);
714                 } else if (!g_ascii_strcasecmp(tag->key, "album")) {
715                         mmfile_free(formatContext->album);
716                         formatContext->album = g_strdup(tag->value);
717                 } else if (!g_ascii_strcasecmp(tag->key, "album_artist")) {
718                         mmfile_free(formatContext->album_artist);
719                         formatContext->album_artist = g_strdup(tag->value);
720                 } else if (!g_ascii_strcasecmp(tag->key, "copyright")) {
721                         mmfile_free(formatContext->copyright);
722                         formatContext->copyright = g_strdup(tag->value);
723                 } else if (!g_ascii_strcasecmp(tag->key, "comment")) {
724                         mmfile_free(formatContext->comment);
725                         formatContext->comment = g_strdup(tag->value);
726                 } else if (!g_ascii_strcasecmp(tag->key, "description")) {
727                         mmfile_free(formatContext->description);
728                         formatContext->description = g_strdup(tag->value);
729                 } else if (!g_ascii_strcasecmp(tag->key, "genre")) {
730                         mmfile_free(formatContext->genre);
731                         formatContext->genre = g_strdup(tag->value);
732                 } else if (!g_ascii_strcasecmp(tag->key, "date")) {
733                         mmfile_free(formatContext->year);
734                         formatContext->year = g_strdup(tag->value);
735                 } else if (!g_ascii_strcasecmp(tag->key, "creation_time")) {
736                         mmfile_free(formatContext->recDate);
737                         formatContext->recDate = g_strdup(tag->value);
738                 } else if ((!g_ascii_strcasecmp(tag->key, "track")) || (!g_ascii_strcasecmp(tag->key, "tracknumber"))) {
739                         mmfile_free(formatContext->tagTrackNum);
740                         formatContext->tagTrackNum = g_strdup(tag->value);
741                 } else if (!g_ascii_strcasecmp(tag->key, "lyrics")) {
742                         mmfile_free(formatContext->unsyncLyrics);
743                         formatContext->unsyncLyrics = g_strdup(tag->value);
744                 } else if (!g_ascii_strcasecmp(tag->key, "spherical-video")) {
745                         ParseSpatialVideoMetadataFromXMLString(tag->value, formatContext);
746                 } else if (!g_ascii_strcasecmp(tag->key, "metadata_block_picture")) {
747                         __fill_picture_in_context(tag->value, formatContext);
748                 } else {
749                         debug_msg(RELEASE, "Not support metadata. [%s:%s]", tag->key, tag->value);
750                 }
751         }
752 }
753
754
755 int mmfile_format_read_tag_ffmpg(MMFileFormatContext *formatContext)
756 {
757         AVFormatContext *pFormatCtx = NULL;
758         unsigned int idx = 0;
759
760         mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
761         mm_file_retvm_if_fails(DEBUG, formatContext->privateFormatData, MMFILE_FORMAT_FAIL);
762
763         if (formatContext->formatType == MM_FILE_FORMAT_3GP || formatContext->formatType == MM_FILE_FORMAT_MP4)
764                 MMFileUtilGetMetaDataFromMP4(formatContext);
765
766         if (formatContext->formatType == MM_FILE_FORMAT_MATROSKA)
767                 MMFileUtilGetMetaDataFromMKV(formatContext);
768
769         pFormatCtx = formatContext->privateFormatData;
770
771         /*metadata extracted by ffmpeg*/
772         for (idx = 0; idx < pFormatCtx->nb_streams + 1; idx++) {
773                 AVDictionary *metainfo = NULL;
774                 AVStream *st = NULL;
775
776                 /* Check metadata of normal stream like audio, video, video cover art
777                  * (cover art saved in new stream). refer to mov_read_covr() in ffmpeg.
778                  */
779                 if (idx < pFormatCtx->nb_streams) {
780                         st = pFormatCtx->streams[idx];
781                         if (st != NULL)
782                                 metainfo = st->metadata;
783                 } else {        /*Check metadata of Content */
784                         if (pFormatCtx->metadata != NULL) {
785                                 metainfo = pFormatCtx->metadata;
786                         } else {
787                                 continue;
788                         }
789                 }
790
791                 /*refer to mov_read_covr() in ffmpeg.*/
792                 if (st) {
793                         __fill_artwork_in_context(st, formatContext);
794                         if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
795                                 __fill_rotate_in_context(st, formatContext);
796                 }
797
798                 if (metainfo)
799                         __fill_metainfo_in_context(metainfo, formatContext);
800
801 #ifdef __MMFILE_TEST_MODE__
802                 mmfile_format_print_tags(formatContext);
803 #endif
804         }
805
806         return MMFILE_FORMAT_SUCCESS;
807 }
808
809 int mmfile_format_read_frame_ffmpg(MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
810 {
811         AVFormatContext *pFormatCtx = NULL;
812         AVCodecContext *pVideoCodecCtx = NULL;
813         const AVCodec *pVideoCodec = NULL;
814         AVCodecParameters *pVideoCodecPar = NULL;
815         AVFrame *pFrame = NULL;
816         struct SwsContext *img_convert_ctx = NULL;
817
818         int width = 0;
819         int height = 0;
820         int numBytes = 0;
821         int ret = 0;
822
823         mm_file_retvm_if_fails(DEBUG, formatContext, MMFILE_FORMAT_FAIL);
824         mm_file_retvm_if_fails(DEBUG, formatContext->privateFormatData, MMFILE_FORMAT_FAIL);
825         mm_file_retvm_if_fails(DEBUG, formatContext->videoTotalTrackNum > 0, MMFILE_FORMAT_FAIL);
826         mm_file_retvm_if_fails(DEBUG, frame, MMFILE_FORMAT_FAIL);
827
828         pFormatCtx = formatContext->privateFormatData;
829
830         mm_file_retvm_if_fails(DEBUG, formatContext->videoStreamId != -1, MMFILE_FORMAT_FAIL);
831
832         pVideoCodecPar = pFormatCtx->streams[formatContext->videoStreamId]->codecpar;
833         mm_file_retvm_if_fails(DEBUG, pVideoCodecPar, MMFILE_FORMAT_FAIL);
834
835         pVideoCodec = avcodec_find_decoder(pVideoCodecPar->codec_id);
836         mm_file_retvm_if_fails(DEBUG, pVideoCodec, MMFILE_FORMAT_FAIL);
837
838         pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec);
839         mm_file_retvm_if_fails(DEBUG, pVideoCodecCtx, MMFILE_FORMAT_FAIL);
840
841         if (avcodec_parameters_to_context(pVideoCodecCtx, pVideoCodecPar) < 0) {
842                 debug_error(DEBUG, "error: avcodec_parameters_to_context");
843                 avcodec_free_context(&pVideoCodecCtx);
844                 return MMFILE_FORMAT_FAIL;
845         }
846
847         debug_msg(RELEASE, "flag: 0x%08X", pVideoCodec->capabilities);
848
849         debug_msg(RELEASE, "  AV_CODEC_CAP_DRAW_HORIZ_BAND : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_DRAW_HORIZ_BAND));
850         debug_msg(RELEASE, "  AV_CODEC_CAP_DR1 : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_DR1));
851         debug_msg(RELEASE, "  AV_CODEC_CAP_DELAY : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_DELAY));
852         debug_msg(RELEASE, "  AV_CODEC_CAP_SMALL_LAST_FRAME : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_SMALL_LAST_FRAME));
853         debug_msg(RELEASE, "  AV_CODEC_CAP_EXPERIMENTAL : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_EXPERIMENTAL));
854         debug_msg(RELEASE, "  AV_CODEC_CAP_CHANNEL_CONF : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_CHANNEL_CONF));
855         debug_msg(RELEASE, "  AV_CODEC_CAP_FRAME_THREADS : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_FRAME_THREADS));
856         debug_msg(RELEASE, "  AV_CODEC_CAP_SLICE_THREADS : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_SLICE_THREADS));
857         debug_msg(RELEASE, "  AV_CODEC_CAP_PARAM_CHANGE : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_PARAM_CHANGE));
858         debug_msg(RELEASE, "  AV_CODEC_CAP_OTHER_THREADS : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_OTHER_THREADS));
859         debug_msg(RELEASE, "  AV_CODEC_CAP_VARIABLE_FRAME_SIZE : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE));
860         debug_msg(RELEASE, "  AV_CODEC_CAP_AVOID_PROBING : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_AVOID_PROBING));
861         debug_msg(RELEASE, "  AV_CODEC_CAP_HARDWARE : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_HARDWARE));
862         debug_msg(RELEASE, "  AV_CODEC_CAP_HYBRID : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_HYBRID));
863         debug_msg(RELEASE, "  AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE));
864         debug_msg(RELEASE, "  AV_CODEC_CAP_ENCODER_FLUSH : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_ENCODER_FLUSH));
865         debug_msg(RELEASE, "  AV_CODEC_CAP_ENCODER_RECON_FRAME : %d", (bool)(pVideoCodec->capabilities & AV_CODEC_CAP_ENCODER_RECON_FRAME));
866
867         /*set workaround bug flag*/
868         pVideoCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
869
870         /* this is solution for PLM issue P13091703323 */
871         /* If using thread when decoding frame, the result of decoding is not always same.
872             Thumbnail of video content is different with original file when copying file. */
873         pVideoCodecCtx->thread_type = 0;
874         pVideoCodecCtx->thread_count = 0;
875         if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) {
876                 debug_error(DEBUG, "error: avcodec_open fail.");
877                 return MMFILE_FORMAT_FAIL;
878         }
879
880         /* search & decode */
881         ret = _get_first_good_video_frame(pFormatCtx, pVideoCodecCtx, &pFrame, formatContext->cdis, formatContext->videoStreamId);
882         if (ret != MMFILE_FORMAT_SUCCESS) {
883                 debug_error(DEBUG, "error: get key frame");
884                 goto EXCEPTION;
885         }
886
887         debug_msg(RELEASE, "Video default resolution = [%dx%d]", pVideoCodecCtx->coded_width, pVideoCodecCtx->coded_height);
888         debug_msg(RELEASE, "Video coded resolution = [%dx%d]", pVideoCodecCtx->width, pVideoCodecCtx->height);
889
890         if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
891                 width = pVideoCodecCtx->coded_width;
892                 height = pVideoCodecCtx->coded_height;
893         } else {
894                 width = pVideoCodecCtx->width;
895                 height = pVideoCodecCtx->height;
896         }
897
898         numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, width, height, 1);
899         if (numBytes <= 0) {
900                 debug_error(DEBUG, "error: av_image_get_buffer_size. [%d x %d]", width, height);
901                 goto EXCEPTION;
902         }
903
904         frame->frameData = av_malloc(numBytes);
905         if (!frame->frameData) {
906                 debug_error(DEBUG, "error: av_malloc.");
907                 goto EXCEPTION;
908         }
909
910         uint8_t *dst_data[4];
911         int dst_linesize[4];
912
913         ret = av_image_fill_arrays(dst_data, dst_linesize, frame->frameData, AV_PIX_FMT_RGB24, width, height, 1);
914         if (ret < 0) {
915                 debug_error(DEBUG, "error: av_image_fill_arrays fail. errcode = 0x%08X", ret);
916                 goto EXCEPTION;
917         }
918
919         img_convert_ctx = sws_getContext(width, height, pVideoCodecCtx->pix_fmt, width, height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
920
921         if (NULL == img_convert_ctx) {
922                 debug_error(DEBUG, "failed to get img convert ctx");
923                 goto EXCEPTION;
924         }
925
926         ret = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize, 0, height, dst_data, dst_linesize);
927         if (ret < 0) {
928                 debug_error(DEBUG, "failed to convert image");
929                 sws_freeContext(img_convert_ctx);
930                 img_convert_ctx = NULL;
931                 goto EXCEPTION;
932         }
933
934         sws_freeContext(img_convert_ctx);
935         img_convert_ctx = NULL;
936
937         frame->frameSize = numBytes;
938         frame->frameWidth = width;
939         frame->frameHeight = height;
940         frame->configLenth = 0;
941         frame->frameDataFree = av_free;
942
943         if (pFrame)
944                 av_frame_free(&pFrame);
945
946         avcodec_free_context(&pVideoCodecCtx);
947
948         return MMFILE_FORMAT_SUCCESS;
949
950 EXCEPTION:
951         avcodec_free_context(&pVideoCodecCtx);
952         av_freep(&frame->frameData);
953         av_frame_free(&pFrame);
954
955         return MMFILE_FORMAT_FAIL;
956 }
957
958
959
960 int mmfile_format_close_ffmpg(MMFileFormatContext *formatContext)
961 {
962         if (formatContext) {
963                 AVFormatContext *pFormatCtx = formatContext->privateFormatData;
964
965                 if (pFormatCtx) {
966                         avformat_close_input(&pFormatCtx);
967                         formatContext->privateFormatData = NULL;
968                 }
969         }
970
971         return MMFILE_FORMAT_SUCCESS;
972 }
973
974 /**
975  * return average of difference
976  */
977 static unsigned int _diff_memory(const void *s1, const void *s2, unsigned int n)
978 {
979         char *s = (char *)s1;
980         char *d = (char *)s2;
981         unsigned int i = 0;
982         unsigned int ret = 0;
983         int tmp = 0;
984
985         for (i = 0, ret = 0; i < n; i++) {
986                 if (*s++ != *d++) {
987                         tmp = (*s - *d);
988                         ret += (tmp < 0 ? -tmp : tmp);
989                 }
990         }
991
992         if (n != 0)
993                 ret /= n;
994
995         return ret;
996 }
997
998 /**
999  * compare with center line.
1000  */
1001 static bool __is_good_pgm(unsigned char *buf, int wrap, int xsize, int ysize)
1002 {
1003 #define _MM_CHUNK_NUM                   8                                               /*FIXME*/
1004 #define _MM_CHUNK_LIMIT                 (_MM_CHUNK_NUM / 2)
1005 #define _MM_CHUNK_DIFF_LIMIT    (_MM_CHUNK_LIMIT * 2 + 1)       /*FIXME*/
1006
1007         int i;
1008         int step;
1009         int point;
1010         unsigned char *cnt;             /*center line of image*/
1011         int is_different;
1012         unsigned int sum_diff;
1013         int cnt_offset;
1014
1015         /*set center line*/
1016         step = ysize / _MM_CHUNK_NUM;
1017         cnt_offset = (ysize / 2);
1018         cnt = buf + cnt_offset * wrap;
1019
1020         debug_msg(RELEASE, "checking frame. %p, %d, %d, %d", buf, wrap, xsize, ysize);
1021
1022         /*if too small, always ok return.*/
1023         if (ysize < _MM_CHUNK_NUM)
1024                 return true;
1025
1026         for (point = 0, sum_diff = 0, i = step; i < ysize; i += step) {
1027                 if (i == cnt_offset)
1028                         continue;
1029
1030                 /*binary compare*/
1031                 is_different = _diff_memory(cnt, buf + i * wrap, xsize);
1032                 point += (is_different == 0 ? 0 : 1);
1033                 sum_diff += is_different;
1034
1035                 debug_msg(RELEASE, "check %04d line. %s [%d]", i, (is_different == 0 ? "same" : "different"), is_different);
1036
1037                 if (point < _MM_CHUNK_LIMIT)
1038                         continue;
1039
1040                 if (sum_diff <= _MM_CHUNK_DIFF_LIMIT) {
1041                         debug_msg(RELEASE, "Bad :-(");
1042                         return false;
1043                 }
1044
1045                 debug_msg(RELEASE, "Good :-)");
1046                 return true;
1047         }
1048
1049         return false;
1050 }
1051
1052 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1053 static void _save_pgm(unsigned char *buf, int wrap, int xsize, int ysize, char *filename)
1054 {
1055         FILE *f;
1056         int i;
1057
1058         f = fopen(filename, "w");
1059         if (f) {
1060                 fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
1061                 for (i = 0; i < ysize; i++)
1062                         fwrite(buf + i * wrap, 1, xsize, f);
1063                 fclose(f);
1064         }
1065 }
1066 #endif
1067
1068 static int _get_first_good_video_frame(AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, AVFrame **pFrame, int cdis, int videoStreamId)
1069 {
1070 #define _RETRY_SEARCH_LIMIT             250
1071 #define _KEY_SEARCH_LIMIT               (_RETRY_SEARCH_LIMIT*2)         /*2 = 1 read. some frame need to read one more*/
1072 #define _FRAME_SEARCH_LIMIT             500
1073
1074 #define _RETRY_SEARCH_LIMIT_CDIS                10
1075 #define _KEY_SEARCH_LIMIT_CDIS          (_RETRY_SEARCH_LIMIT*2)         /*2 = 1 read. some frame need to read one more*/
1076 #define _FRAME_SEARCH_LIMIT_CDIS                10
1077
1078         AVPacket *pkt = NULL;
1079
1080         AVFrame *frame = NULL;
1081         AVFrame *tmp_frame = NULL;
1082         AVFrame *first_frame = NULL;
1083
1084         int found = 0;
1085         int i = 0;
1086         int v = 0;
1087         int ret;
1088         int retry = 0;
1089         bool key_detected = false;
1090 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1091         char pgm_name[256] = {0, };
1092 #endif
1093         int key_search_limit = (cdis == 1) ? _KEY_SEARCH_LIMIT_CDIS : _KEY_SEARCH_LIMIT;
1094         int frame_search_limit = (cdis == 1) ? _FRAME_SEARCH_LIMIT_CDIS : _FRAME_SEARCH_LIMIT;
1095
1096         first_frame = av_frame_alloc();
1097         tmp_frame = av_frame_alloc();
1098
1099         if (!first_frame || !tmp_frame) {
1100                 debug_error(DEBUG, "failed to alloc frame.");
1101                 av_frame_free(&first_frame);
1102                 av_frame_free(&tmp_frame);
1103
1104                 return MMFILE_FORMAT_FAIL;
1105         }
1106
1107         debug_msg(RELEASE, "frame: 1. %p, 2. %p", first_frame, tmp_frame);
1108
1109         pCodecCtx->skip_frame = AVDISCARD_BIDIR;
1110         frame = first_frame;
1111
1112         while (i < key_search_limit && v < frame_search_limit) {
1113                 pkt = av_packet_alloc();
1114                 if (!pkt) {
1115                         debug_error(DEBUG, "packet allocation failed.");
1116                         break;
1117                 }
1118
1119                 if (av_read_frame(pFormatCtx, pkt) < 0) {
1120                         debug_error(DEBUG, "read failed. (maybe EOF or broken)");
1121                         break;
1122                 }
1123
1124                 if (pkt->stream_index != videoStreamId)
1125                         goto NEXT;
1126
1127                 v++;
1128                 if (!(pkt->flags & AV_PKT_FLAG_KEY) && !key_detected)
1129                         goto NEXT;
1130
1131 #ifdef __MMFILE_TEST_MODE__
1132                 _dump_av_packet(pkt);
1133 #endif
1134                 i++;
1135                 key_detected = false;
1136                 debug_msg(RELEASE, "video frame: %d, %d, %d", retry, i, v);
1137
1138                 ret = avcodec_send_packet(pCodecCtx, pkt);
1139                 if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
1140                         debug_error(RELEASE, "Error while avcodec_send_packet[%2d]", ret);
1141                         break;
1142                 }
1143
1144                 ret = avcodec_receive_frame(pCodecCtx, frame);
1145                 if (ret < 0) {
1146                         if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
1147                                 debug_msg(RELEASE, "decode not completed.");
1148                                 key_detected = true;
1149                                 goto NEXT;
1150                         }
1151                         debug_warning(DEBUG, "Error while decoding frame %dth", i);
1152                         goto NEXT;
1153                 }
1154
1155                 if (!(frame->flags & AV_FRAME_FLAG_KEY)) {
1156                         debug_msg(RELEASE, "skip (not key frame).");
1157 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1158                         memset(pgm_name, 0x00, sizeof(pgm_name));
1159                         snprintf(pgm_name, sizeof(pgm_name), "./not_key_%d_%d_%d.pgm", retry, i, v);
1160                         _save_pgm(frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height, pgm_name);
1161 #endif
1162                         goto NEXT;
1163                 }
1164
1165                 debug_msg(RELEASE, "key frame!");
1166 #ifdef MMFILE_FORMAT_DEBUG_DUMP
1167                 memset(pgm_name, 0x00, sizeof(pgm_name));
1168                 snprintf(pgm_name, sizeof(pgm_name), "./key_%d_%d_%d.pgm", retry, i, v);
1169                 _save_pgm(frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height, pgm_name);
1170 #endif
1171                 found++;
1172
1173                 if (__is_good_pgm(frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height)) {
1174                         debug_msg(RELEASE, "is good frame.");
1175                         break;
1176                 }
1177
1178                 debug_warning(RELEASE, "not good fame. retry scanning.");
1179                 i = 0;
1180                 v = 0;
1181                 retry++;
1182
1183                 /*set buffer frame*/
1184                 frame = tmp_frame;
1185
1186                 if (retry > _RETRY_SEARCH_LIMIT)
1187                         break;
1188 NEXT:
1189                 av_packet_free(&pkt);
1190         }
1191
1192         /*free pkt after loop breaking*/
1193         av_packet_free(&pkt);
1194
1195         debug_msg(RELEASE, "found: %d, retry: %d", found, retry);
1196
1197         /*set decode frame to output*/
1198         if (found > 0) {
1199                 if (retry == 0 || found == retry) {
1200                         *pFrame = first_frame;
1201                         av_frame_free(&tmp_frame);
1202                 } else {
1203                         *pFrame = tmp_frame;
1204                         av_frame_free(&first_frame);
1205                 }
1206         } else {
1207                 av_frame_free(&first_frame);
1208                 av_frame_free(&tmp_frame);
1209         }
1210
1211         debug_msg(RELEASE, "out frame: %p", *pFrame);
1212
1213         pCodecCtx->skip_frame = AVDISCARD_NONE;
1214
1215         return (found > 0) ? MMFILE_FORMAT_SUCCESS : MMFILE_FORMAT_FAIL;
1216 }