071e8c00603868ba6b69b805799a2f5bd4e79b6d
[platform/core/multimedia/libmm-fileinfo.git] / formats / ffmpeg / mm_file_format_frame.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 #include <stdbool.h>
22 #include <libavformat/avformat.h>
23 #include <libavcodec/avcodec.h>
24 #include <libswscale/swscale.h>
25
26 #include <mm_types.h>
27 #include "mm_file_debug.h"
28 #include "mm_file_formats.h"
29 #include "mm_file_utils.h"
30 #include "mm_file_format_ffmpeg_mem.h"
31 #include "mm_file_format_frame.h"
32
33 #define MILLION 1000000
34 #ifdef MMFILE_FORMAT_DEBUG_DUMP
35 static void __save_frame(AVFrame *pFrame, int width, int height, int iFrame);
36
37 void __save_frame(AVFrame *pFrame, int width, int height, int iFrame)
38 {
39         FILE *pFile;
40         char szFilename[32];
41         int y;
42         /* Open file */
43         sprintf(szFilename, "frame%d.ppm", iFrame);
44         pFile = fopen(szFilename, "wb");
45         if (pFile == NULL)
46                 return;
47
48         /* Write header */
49         fprintf(pFile, "P6\n%d %d\n255\n", width, height);
50         /* Write pixel data */
51         for (y = 0; y < height; y++)
52                 fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile);
53
54         /* Close file */
55         fclose(pFile);
56 }
57 #endif
58
59 static int __getMimeType(int formatId, char *mimeType, int buf_size)
60 {
61         int ret = 0;    /*default: success*/
62
63         switch (formatId) {
64                 case MM_FILE_FORMAT_3GP:
65                 case MM_FILE_FORMAT_MP4:
66                         snprintf(mimeType, buf_size, "video/3gpp");
67                         break;
68                 case MM_FILE_FORMAT_ASF:
69                 case MM_FILE_FORMAT_WMA:
70                 case MM_FILE_FORMAT_WMV:
71                         snprintf(mimeType, buf_size, "video/x-ms-asf");
72                         break;
73                 case  MM_FILE_FORMAT_AVI:
74                         snprintf(mimeType, buf_size, "video/avi");
75                         break;
76                 case MM_FILE_FORMAT_OGG:
77                         snprintf(mimeType, buf_size, "video/ogg");
78                         break;
79                 case MM_FILE_FORMAT_REAL:
80                         snprintf(mimeType, buf_size, "video/vnd.rn-realmedia");
81                         break;
82                 case MM_FILE_FORMAT_AMR:
83                         snprintf(mimeType, buf_size, "audio/AMR");
84                         break;
85                 case MM_FILE_FORMAT_AAC:
86                         snprintf(mimeType, buf_size, "audio/aac");
87                         break;
88                 case MM_FILE_FORMAT_MP3:
89                         snprintf(mimeType, buf_size, "audio/mp3");
90                         break;
91                 case MM_FILE_FORMAT_AIFF:
92                 case MM_FILE_FORMAT_WAV:
93                         snprintf(mimeType, buf_size, "audio/wave");
94                         break;
95                 case MM_FILE_FORMAT_MID:
96                         snprintf(mimeType, buf_size, "audio/midi");
97                         break;
98                 case MM_FILE_FORMAT_MMF:
99                         snprintf(mimeType, buf_size, "audio/mmf");
100                         break;
101                 case MM_FILE_FORMAT_DIVX:
102                         snprintf(mimeType, buf_size, "video/divx");
103                         break;
104                 case MM_FILE_FORMAT_IMELODY:
105                         snprintf(mimeType, buf_size, "audio/iMelody");
106                         break;
107                 case MM_FILE_FORMAT_JPG:
108                         snprintf(mimeType, buf_size, "image/jpeg");
109                         break;
110                 case MM_FILE_FORMAT_AU:
111                         snprintf(mimeType, buf_size, "audio/basic");
112                         break;
113                 case MM_FILE_FORMAT_VOB:
114                         snprintf(mimeType, buf_size, "video/dvd");
115                         break;
116                 case MM_FILE_FORMAT_FLV:
117                         snprintf(mimeType, buf_size, "video/x-flv");
118                         break;
119                 case MM_FILE_FORMAT_QT:
120                         snprintf(mimeType, buf_size, "video/quicktime");
121                         break;
122                 case MM_FILE_FORMAT_MATROSKA:
123                         snprintf(mimeType, buf_size, "video/x-matroska");
124                         break;
125                 case MM_FILE_FORMAT_FLAC:
126                         snprintf(mimeType, buf_size, "audio/x-flac");
127                         break;
128                 case MM_FILE_FORMAT_M2TS:
129                         snprintf(mimeType, buf_size, "video/MP2T");
130                         break;
131                 case MM_FILE_FORMAT_M2PS:
132                         snprintf(mimeType, buf_size, "video/MP2P");
133                         break;
134                 case MM_FILE_FORMAT_M1VIDEO:
135                         snprintf(mimeType, buf_size, "video/mpeg");
136                         break;
137                 case MM_FILE_FORMAT_M1AUDIO:
138                         snprintf(mimeType, buf_size, "audio/x-mpegaudio");
139                         break;
140                 default:
141                         ret = -1;
142                         break;
143         }
144
145         debug_msg(RELEASE, "id: %d, mimetype: %s\n", formatId, mimeType);
146
147         return ret;
148 }
149
150 extern const struct {
151         int (*Open)(MMFileFormatContext *fileContext);
152         int (*Valid)(MMFileIOHandle *pFileIO, const char *mmfileuri, int mp3FrameCnt);
153 } MMFileFunc[MM_FILE_FORMAT_NUM + 1];
154 static int __get_fileformat(const char *urifilename, int *format)
155 {
156         int index;
157         int ret = 0;
158         MMFileIOHandle *fp = NULL;
159
160         debug_error(DEBUG, "%s\n", urifilename);
161
162         ret = mmfile_open(&fp, urifilename, MMFILE_RDONLY);
163
164         if (ret == MMFILE_IO_FAILED) {
165                 debug_error(DEBUG, "error: mmfile_open\n");
166                 if (fp)
167                         mmfile_close(fp);
168                 return MMFILE_FORMAT_FAIL;
169         }
170
171         for (index = 0; index < MM_FILE_FORMAT_NUM; index++) {
172                 debug_msg(RELEASE, "search index = [%d]\n", index);
173
174                 switch (index) {
175                         case MM_FILE_FORMAT_QT:
176                         case MM_FILE_FORMAT_3GP:
177                         case MM_FILE_FORMAT_MP4:
178                                 *format = MM_FILE_FORMAT_3GP;
179                                 break;
180
181                         case MM_FILE_FORMAT_ASF:
182                         case MM_FILE_FORMAT_WMA:
183                         case MM_FILE_FORMAT_WMV:
184                                 *format = MM_FILE_FORMAT_ASF;
185                                 break;
186
187                         case MM_FILE_FORMAT_DIVX:
188                         case MM_FILE_FORMAT_AVI:
189                                 *format = MM_FILE_FORMAT_AVI;
190                                 break;
191
192                         case MM_FILE_FORMAT_MATROSKA:
193                         case MM_FILE_FORMAT_FLV:
194                         case MM_FILE_FORMAT_M2TS:
195                         case MM_FILE_FORMAT_M2PS:
196                         case MM_FILE_FORMAT_REAL:
197                         case MM_FILE_FORMAT_M1AUDIO:
198                         case MM_FILE_FORMAT_M1VIDEO:
199                                 *format = index;
200                                 break;
201
202                         default: {
203                                 *format = MM_FILE_FORMAT_NUM;
204                                 debug_error(DEBUG, "error: not supported or invaild format enum[%d]\n", index);
205                                 break;
206                         }
207                 }
208
209                 if (MMFileFunc[*format].Valid!= NULL && MMFileFunc[*format].Valid(fp, NULL, 0)) {
210                         goto FILE_FORMAT_SUCCESS;
211                 }
212         }
213
214         if (index == MM_FILE_FORMAT_NUM) {
215                 debug_error(DEBUG, "Can't probe file type\n");
216         }
217
218         *format = -1;
219
220         if (fp)
221                 mmfile_close(fp);
222
223         return MMFILE_FORMAT_FAIL;
224
225 FILE_FORMAT_SUCCESS:
226         if (fp)
227                 mmfile_close(fp);
228
229         return MMFILE_FORMAT_SUCCESS;
230 }
231
232 static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
233 {
234
235         unsigned int i = 0;
236         int len = 0;
237         int ret = MMFILE_FORMAT_SUCCESS;
238         int videoStream = -1;
239         int key_detected = 0;
240         int got_picture = 0;
241         int64_t pos = timestamp;
242         bool find = false;
243         bool first_seek = true;
244         int64_t pts = 0;
245         AVCodecContext *pVideoCodecCtx = NULL;
246         AVCodec *pVideoCodec = NULL;
247         AVFrame *pFrame = NULL, *pFrameRGB = NULL;
248         AVPacket packet;
249
250         /* Retrieve stream information */
251         if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
252                 debug_error(DEBUG, "error : av_find_stream_info failed");
253                 ret = MMFILE_FORMAT_FAIL;
254                 goto exception; /* Couldn't find stream information */
255         }
256
257         /* Find the first video stream */
258         for (i = 0; i < pFormatCtx->nb_streams; i++) {
259                 if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
260                         videoStream = i;
261                         break;
262                 }
263         }
264
265         if (videoStream == -1) {
266                 debug_error(DEBUG, "error : videoStream == -1");
267                 ret = MMFILE_FORMAT_FAIL;
268                 goto exception; /* Didn't find a video stream */
269         }
270
271         /* Get a pointer to the codec context for the video stream */
272         pVideoCodecCtx = pFormatCtx->streams[videoStream]->codec;
273         if (pVideoCodecCtx == NULL) {
274                 debug_error(DEBUG, "invalid param\n");
275                 ret = MMFILE_FORMAT_FAIL;
276                 goto exception;
277         }
278
279         /* Find the decoder for the video stream */
280         pVideoCodec = avcodec_find_decoder(pVideoCodecCtx->codec_id);
281         if (pVideoCodec == NULL) {
282                 debug_error(DEBUG, "error : Unsupported codec");
283                 ret = MMFILE_FORMAT_FAIL;
284                 goto exception; /* Codec not found */
285         }
286
287         /* Open codec */
288         pVideoCodecCtx->thread_type = 0;
289         pVideoCodecCtx->thread_count = 0;
290         if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) {
291                 debug_error(DEBUG, "error : avcodec_open failed");
292                 ret = MMFILE_FORMAT_FAIL;
293                 goto exception;; /*Could not open codec */
294         }
295
296         /* Storing Data  */
297         /* Allocate video frame */
298         pFrame = av_frame_alloc();
299         if (pFrame == NULL) {
300                 debug_error(DEBUG, "error: pFrame is NULL\n");
301                 ret = MMFILE_FORMAT_FAIL;
302                 goto exception;
303         }
304
305         /* Allocate an AVFrame structure */
306         pFrameRGB = av_frame_alloc();
307         if (pFrameRGB == NULL) {
308                 debug_error(DEBUG, "error: pFrameRGB is NULL\n");
309                 ret = MMFILE_FORMAT_FAIL;
310                 goto exception;
311         }
312
313         /* Seeking */
314         AVStream *pStream = pFormatCtx->streams[videoStream];
315         double duration = (double) pFormatCtx->duration / AV_TIME_BASE;
316 #if 0
317         if (duration <= 0) {
318                 double tmpDuration = 0.0;
319
320                 if (pStream->codec->bit_rate > 0 && pFormatCtx->file_size > 0) {
321                         if (pStream->codec->bit_rate >= 8)
322                                 tmpDuration = 0.9 * pFormatCtx->file_size / (pStream->codec->bit_rate / 8);
323
324                         if (tmpDuration > 0)
325                                 duration = tmpDuration;
326                 }
327         }
328 #endif
329         duration = duration * MILLION;
330         if ((duration <= 0) || (duration <= pos)) {
331                 debug_error(DEBUG, "duration error duration[%f] pos[%lld]", duration, pos);
332                 ret = MMFILE_FORMAT_FAIL;
333                 goto exception;
334         }
335
336         if (is_accurate)
337                 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_ANY);
338         else
339                 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
340
341         /* Reading Data */
342         int64_t tmpPts = 0;
343 #ifdef __MMFILE_TEST_MODE__
344         int idx = 0;
345 #endif
346
347         av_init_packet(&packet);
348
349         while (av_read_frame(pFormatCtx, &packet) >= 0) {
350                 got_picture = 0;
351
352                 /* Is this a packet from the video stream? */
353                 if (packet.stream_index == videoStream) {
354                         #ifdef __MMFILE_TEST_MODE__
355                         debug_msg(RELEASE, "find Video Stream+++++++[%2d]", idx++);
356                         #endif
357
358                         /* Decode video frame*/
359                         len = avcodec_decode_video2(pVideoCodecCtx, pFrame, &got_picture, &packet);
360                         if (len < 0) {
361                                 debug_warning(DEBUG, "Error while decoding frame");
362                         } else if ((packet.flags & AV_PKT_FLAG_KEY) || (key_detected == 1)) {
363
364                                 key_detected = 0;
365
366                                 if (first_seek || !is_accurate) {
367                                         /* This is first seeking or not accurate mode.
368                                         Sometimes flag is AV_PKT_FLAG_KEY but got_picture is NULL.
369                                         first_seek is used when accurate mode and when time stamp's frame is not key frame.
370                                         Go back to previousto Key frame and decode frame until time stamp's frame*/
371
372                                         if (got_picture) {
373                                                 if (pFrame->key_frame) {
374                                                         debug_msg(RELEASE, "find Video Stream+++++++Find key frame");
375                                                 } else {
376                                                         debug_msg(RELEASE, "find Video Stream+++++++ not key frame");
377                                                 }
378
379                                                 /*eventhough decoded pFrame is not key frame, if packet.flags is AV_PKT_FLAG_KEY then can extract frame*/
380                                                 find = true;
381
382                                         } else {
383                                                 debug_msg(RELEASE, "find Video Stream+++++++Find key but no frame");
384                                                 key_detected = 1;
385                                         }
386                                 }
387                         } else {
388                                 if (is_accurate) {
389                                         if (first_seek) {
390                                                 pts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
391                                                 first_seek = false;
392
393                                                 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
394                                         } else {
395                                                 tmpPts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
396                                                 if (pts == tmpPts)
397                                                         find = true;
398                                         }
399                                 }
400                         }
401
402                         if (find && got_picture) {
403                                 break;
404                         }
405                 }
406
407                 /* Free the packet that was allocated by av_read_frame*/
408                 av_free_packet(&packet);
409                 av_init_packet(&packet);
410         }
411
412         /*free pkt after loop breaking*/
413         av_free_packet(&packet);
414
415         /* Did we get a video frame?*/
416         if (got_picture && find) {
417
418                 debug_msg(RELEASE, "Find Frame");
419
420                 /* return frame infromations*/
421                 if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
422                         *width = pVideoCodecCtx->coded_width;
423                         *height = pVideoCodecCtx->coded_height;
424                 } else {
425                         *width = pVideoCodecCtx->width;
426                         *height = pVideoCodecCtx->height;
427                 }
428
429                 *size = avpicture_get_size(AV_PIX_FMT_RGB24, *width, *height);
430
431                 if (*size > 0)
432                         *frame = mmfile_malloc(*size);
433
434                 if (NULL == *frame) {
435                         debug_error(DEBUG, "error: avpicture_get_size. [%d]\n", *size);
436                         ret = MMFILE_FORMAT_FAIL;
437                         goto exception;
438                 }
439
440                 debug_msg(RELEASE, "size : %d", *size);
441                 debug_msg(RELEASE, "width : %d", *width);
442                 debug_msg(RELEASE, "height : %d", *height);
443                 debug_msg(RELEASE, "frame : %p", *frame);
444
445                 ret = avpicture_fill((AVPicture *)pFrameRGB, *frame, AV_PIX_FMT_RGB24, *width, *height);
446                 if (ret < 0) {
447                         debug_error(DEBUG, "error: avpicture_fill fail. errcode = 0x%08X\n", ret);
448                         ret = MMFILE_FORMAT_FAIL;
449                         goto exception;
450                 }
451
452                 struct SwsContext *img_convert_ctx = NULL;
453
454                 img_convert_ctx = sws_getContext(*width, *height, pVideoCodecCtx->pix_fmt,
455                                                 *width, *height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
456
457                 if (NULL == img_convert_ctx) {
458                         debug_error(DEBUG, "failed to get img convet ctx\n");
459                         ret = MMFILE_FORMAT_FAIL;
460                         goto exception;
461                 }
462
463                 ret = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize,
464                                         0, *height, pFrameRGB->data, pFrameRGB->linesize);
465                 if (ret < 0) {
466                         debug_error(DEBUG, "failed to convet image\n");
467                         sws_freeContext(img_convert_ctx);
468                         img_convert_ctx = NULL;
469                         ret = MMFILE_FORMAT_FAIL;
470                         goto exception;
471                 }
472
473                 sws_freeContext(img_convert_ctx);
474                 img_convert_ctx = NULL;
475
476 #ifdef MMFILE_FORMAT_DEBUG_DUMP
477                 __save_frame(pFrameRGB, pVideoCodecCtx->width, pVideoCodecCtx->height, (int)(pos / 1000));
478 #endif
479         } else {
480                 debug_error(DEBUG, "Not Found Proper Frame[%d][%d]", got_picture, find);
481                 ret = MMFILE_FORMAT_FAIL;
482                 goto exception;
483         }
484
485         if (pFrame)                     av_free(pFrame);
486         if (pFrameRGB)          av_free(pFrameRGB);
487         if (pVideoCodecCtx)     avcodec_close(pVideoCodecCtx);
488
489         return MMFILE_FORMAT_SUCCESS;
490
491 exception:
492         if (*frame) {
493                 mmfile_free(*frame);
494                 *frame = NULL;
495         }
496         if (pFrame)                     av_free(pFrame);
497         if (pFrameRGB)          av_free(pFrameRGB);
498         if (pVideoCodecCtx)     avcodec_close(pVideoCodecCtx);
499
500         return ret;
501 }
502
503 int mmfile_format_get_frame(const char *path, double timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
504 {
505         int ret = MMFILE_FORMAT_SUCCESS;
506         AVFormatContext *pFormatCtx = NULL;
507
508         if (!size || !width || !height) {
509                 return MMFILE_FORMAT_FAIL;
510         }
511
512         av_register_all();
513
514         /* Open video file */
515         if (avformat_open_input(&pFormatCtx, path, NULL, NULL) != 0) {
516                 debug_error(DEBUG, "error : avformat_open_input failed");
517                 return MMFILE_FORMAT_FAIL; /* Couldn't open file */
518         }
519
520         if (!pFormatCtx) {
521                 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.\n");
522                 ret = MMFILE_FORMAT_FAIL;
523                 goto exception;
524         }
525
526         ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
527
528 exception:
529         /* Close video file */
530         if (pFormatCtx) avformat_close_input(&pFormatCtx);
531
532         return ret;
533 }
534
535 int mmfile_format_get_frame_from_memory(const void *data, unsigned int datasize, double timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
536 {
537         int ret = MMFILE_FORMAT_SUCCESS;
538         int format = -1;
539         char mimeType[MMFILE_MIMETYPE_MAX_LEN] = {0, };
540         char ffmpegFormatName[MMFILE_FILE_FMT_MAX_LEN] = {0, };
541         char tempURIBuffer[MMFILE_URI_MAX_LEN] = {0, };
542         char *urifilename = NULL;
543         AVFormatContext *pFormatCtx = NULL;
544         AVInputFormat *grab_iformat = NULL;
545
546         if (!size || !width || !height) {
547                 return MMFILE_FORMAT_FAIL;
548         }
549
550         av_register_all();
551
552         snprintf(tempURIBuffer, MMFILE_URI_MAX_LEN,  "%s%u:%u", MMFILE_MEM_URI, (unsigned int)data, datasize);
553         urifilename = mmfile_strdup(tempURIBuffer);
554         if (!urifilename) {
555                 debug_error(DEBUG, "error: uri is NULL\n");
556                 return MMFILE_FORMAT_FAIL;
557         }
558
559         mmfile_register_io_all();
560
561         ret = __get_fileformat(urifilename, &format);
562         if (ret != MMFILE_FORMAT_SUCCESS) {
563                 debug_error(DEBUG, "error: file format is invalid\n");
564                 return MMFILE_FORMAT_FAIL;
565         }
566
567         ffurl_register_protocol(&MMFileMEMProtocol);
568
569         if (__getMimeType(format, mimeType, MMFILE_MIMETYPE_MAX_LEN) < 0) {
570                 debug_error(DEBUG, "error: Error in MIME Type finding\n");
571                 return MMFILE_FORMAT_FAIL;
572         }
573
574         memset(ffmpegFormatName, 0x00, MMFILE_FILE_FMT_MAX_LEN);
575
576         ret = mmfile_util_get_ffmpeg_format(mimeType, ffmpegFormatName);
577
578         if (MMFILE_UTIL_SUCCESS != ret) {
579                 debug_error(DEBUG, "error: mmfile_util_get_ffmpeg_format\n");
580                 return MMFILE_FORMAT_FAIL;
581         }
582
583         grab_iformat = av_find_input_format(ffmpegFormatName);
584
585         if (NULL == grab_iformat) {
586                 debug_error(DEBUG, "error: cannot find format\n");
587                 goto exception;
588         }
589
590         ret = avformat_open_input(&pFormatCtx, urifilename, grab_iformat, NULL);
591         if (ret < 0) {
592                 debug_error(DEBUG, "error: cannot open %s %d\n", urifilename, ret);
593                 goto exception;
594         }
595
596         if (!pFormatCtx) {
597                 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.\n");
598                 ret = MMFILE_FORMAT_FAIL;
599                 goto exception;
600         }
601
602         ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
603
604 exception:
605         /* Close video file */
606         if (pFormatCtx) avformat_close_input(&pFormatCtx);
607
608         ffurl_deregister_protocol(&MMFileMEMProtocol);
609
610         return ret;
611 }