Fix Memory leak
[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 #include <libavutil/imgutils.h>
26
27 #include <mm_types.h>
28 #include "mm_file_debug.h"
29 #include "mm_file_formats.h"
30 #include "mm_file_utils.h"
31 #include "mm_file_format_frame.h"
32
33 #define MILLION 1000000
34 #ifdef MMFILE_FORMAT_DEBUG_DUMP
35 static void __save_frame(uint8_t *const dst[], const int dstStride[], int width, int height, int iFrame);
36
37 void __save_frame(uint8_t *const dst[], const int dstStride[], int width, int height, int iFrame)
38 {
39         FILE *pFile;
40         char szFilename[32] = {0,};
41         int y = 0;
42         /* Open file */
43
44         memset(szFilename, 0x00, sizeof(szFilename));
45         snprintf(szFilename, sizeof(szFilename), "frame%d.ppm", iFrame);
46         pFile = fopen(szFilename, "wb");
47         if (pFile == NULL)
48                 return;
49
50         /* Write header */
51         fprintf(pFile, "P6\n%d %d\n255\n", width, height);
52         /* Write pixel data */
53         for (y = 0; y < height; y++)
54                 fwrite(dst[0] + y * dstStride[0], 1, width * 3, pFile);
55
56         /* Close file */
57         fclose(pFile);
58 }
59 #endif
60
61 static int _mmf_mem_read(void *opaque, uint8_t *buf, int size);
62 static int64_t _mmf_mem_seek(void *opaque, int64_t pos, int whence);
63
64 typedef struct {
65         unsigned char *ptr;
66         long long size;
67         long long offset;
68         int     state;
69 } MMFmemIOHandle;
70
71 static int _mmf_mem_open(MMFmemIOHandle **handle, const char *filename)
72 {
73         MMFmemIOHandle *memHandle = NULL;
74         char **splitedString = NULL;
75
76         filename += strlen(MMFILE_MEM_URI);
77
78         splitedString = mmfile_strsplit(filename, ":");
79         if (splitedString == NULL) {
80                 debug_error(DEBUG, "invalid param\n");
81                 return MMFILE_IO_FAILED;
82         }
83
84         if (!splitedString[0] || !splitedString[1]) {
85                 debug_error(DEBUG, "invalid param\n");
86                 goto exception;
87         }
88
89         memHandle = mmfile_malloc(sizeof(MMFmemIOHandle));
90         if (!memHandle) {
91                 debug_error(DEBUG, "error: mmfile_malloc memHandle\n");
92                 goto exception;
93         }
94
95         memHandle->ptr = (unsigned char *)atoll(splitedString[0]);      /*memory allocation address changed. memHandle->ptr = (unsigned char*)atoi(splitedString[0]); */
96         memHandle->size = atoi(splitedString[1]);
97         memHandle->offset = 0;
98         memHandle->state = 0;
99
100         *handle = memHandle;
101
102         if (splitedString) {
103                 mmfile_strfreev(splitedString);
104         }
105
106         return MMFILE_IO_SUCCESS;
107
108 exception:
109
110         if (splitedString) {
111                 mmfile_strfreev(splitedString);
112         }
113
114         return MMFILE_IO_FAILED;
115 }
116
117 static int _mmf_mem_read(void *opaque, uint8_t *buf, int size)
118 {
119         MMFmemIOHandle *memHandle = NULL;
120         const unsigned char *c = NULL;
121         int len = 0;
122
123         if (!opaque || !buf) {
124                 debug_error(DEBUG, "invalid para\n");
125                 return MMFILE_UTIL_FAIL;
126         }
127
128         memHandle = opaque;
129
130         if (!memHandle->ptr) {
131                 debug_error(DEBUG, "invalid para\n");
132                 return MMFILE_UTIL_FAIL;
133         }
134
135         if (memHandle->offset >= memHandle->size) {
136                 /* for some file formats last file read */
137                 debug_error(DEBUG, "File Read is beyond the file Size\n");
138                 return MMFILE_UTIL_FAIL;
139
140         }
141
142         c = memHandle->ptr + memHandle->offset;
143
144         if (memHandle->state != EOF) {
145                 len = size;
146                 if (len + memHandle->offset > memHandle->size) {
147                         len = memHandle->size - memHandle->offset;
148                 }
149         }
150
151         memcpy(buf, c, len);
152
153         memHandle->offset += len;
154
155         if (memHandle->offset == memHandle->size) {
156                 memHandle->state = EOF;
157         }
158
159         return len;
160 }
161
162 static int64_t _mmf_mem_seek(void *opaque, int64_t pos, int whence)
163 {
164         MMFmemIOHandle *memHandle = NULL;
165         long long tmp_offset = 0;
166
167         if (!opaque) {
168                 debug_error(DEBUG, "invalid para\n");
169                 return MMFILE_UTIL_FAIL;
170         }
171
172         memHandle = opaque;
173
174         switch (whence) {
175         case SEEK_SET:
176                 tmp_offset = 0 + pos;
177                 break;
178         case SEEK_CUR:
179                 tmp_offset = memHandle->offset + pos;
180                 break;
181         case SEEK_END:
182                 tmp_offset = memHandle->size + pos;
183                 break;
184         case AVSEEK_SIZE:       /*FFMPEG specific*/
185                 return memHandle->size;
186         default:
187                 return MMFILE_UTIL_FAIL;
188         }
189
190         /*check validation*/
191         if (tmp_offset < 0 && tmp_offset > memHandle->size) {
192                 debug_error(DEBUG, "invalid file offset\n");
193                 return MMFILE_UTIL_FAIL;
194         }
195
196         /*set */
197         memHandle->state = (tmp_offset >= memHandle->size) ? EOF : !EOF;
198         memHandle->offset = (unsigned int) tmp_offset;
199
200         return tmp_offset;
201 }
202
203 static int __getMimeType(int formatId, char *mimeType, int buf_size)
204 {
205         int ret = 0;    /*default: success*/
206
207         switch (formatId) {
208         case MM_FILE_FORMAT_3GP:
209         case MM_FILE_FORMAT_MP4:
210                 snprintf(mimeType, buf_size, "video/3gpp");
211                 break;
212         case MM_FILE_FORMAT_ASF:
213         case MM_FILE_FORMAT_WMA:
214         case MM_FILE_FORMAT_WMV:
215                 snprintf(mimeType, buf_size, "video/x-ms-asf");
216                 break;
217         case  MM_FILE_FORMAT_AVI:
218                 snprintf(mimeType, buf_size, "video/avi");
219                 break;
220         case MM_FILE_FORMAT_OGG:
221                 snprintf(mimeType, buf_size, "video/ogg");
222                 break;
223         case MM_FILE_FORMAT_REAL:
224                 snprintf(mimeType, buf_size, "video/vnd.rn-realmedia");
225                 break;
226         case MM_FILE_FORMAT_AMR:
227                 snprintf(mimeType, buf_size, "audio/AMR");
228                 break;
229         case MM_FILE_FORMAT_AAC:
230                 snprintf(mimeType, buf_size, "audio/aac");
231                 break;
232         case MM_FILE_FORMAT_MP3:
233                 snprintf(mimeType, buf_size, "audio/mp3");
234                 break;
235         case MM_FILE_FORMAT_AIFF:
236         case MM_FILE_FORMAT_WAV:
237                 snprintf(mimeType, buf_size, "audio/wave");
238                 break;
239         case MM_FILE_FORMAT_MID:
240                 snprintf(mimeType, buf_size, "audio/midi");
241                 break;
242         case MM_FILE_FORMAT_MMF:
243                 snprintf(mimeType, buf_size, "audio/mmf");
244                 break;
245         case MM_FILE_FORMAT_DIVX:
246                 snprintf(mimeType, buf_size, "video/divx");
247                 break;
248         case MM_FILE_FORMAT_IMELODY:
249                 snprintf(mimeType, buf_size, "audio/iMelody");
250                 break;
251         case MM_FILE_FORMAT_JPG:
252                 snprintf(mimeType, buf_size, "image/jpeg");
253                 break;
254         case MM_FILE_FORMAT_AU:
255                 snprintf(mimeType, buf_size, "audio/basic");
256                 break;
257         case MM_FILE_FORMAT_VOB:
258                 snprintf(mimeType, buf_size, "video/dvd");
259                 break;
260         case MM_FILE_FORMAT_FLV:
261                 snprintf(mimeType, buf_size, "video/x-flv");
262                 break;
263         case MM_FILE_FORMAT_QT:
264                 snprintf(mimeType, buf_size, "video/quicktime");
265                 break;
266         case MM_FILE_FORMAT_MATROSKA:
267                 snprintf(mimeType, buf_size, "video/x-matroska");
268                 break;
269         case MM_FILE_FORMAT_FLAC:
270                 snprintf(mimeType, buf_size, "audio/x-flac");
271                 break;
272         case MM_FILE_FORMAT_M2TS:
273                 snprintf(mimeType, buf_size, "video/MP2T");
274                 break;
275         case MM_FILE_FORMAT_M2PS:
276                 snprintf(mimeType, buf_size, "video/MP2P");
277                 break;
278         case MM_FILE_FORMAT_M1VIDEO:
279                 snprintf(mimeType, buf_size, "video/mpeg");
280                 break;
281         case MM_FILE_FORMAT_M1AUDIO:
282                 snprintf(mimeType, buf_size, "audio/x-mpegaudio");
283                 break;
284         default:
285                 ret = -1;
286                 break;
287         }
288
289         debug_msg(RELEASE, "id: %d, mimetype: %s\n", formatId, mimeType);
290
291         return ret;
292 }
293
294 extern const struct {
295         int (*Open)(MMFileFormatContext *fileContext);
296         int (*Valid)(MMFileIOHandle *pFileIO, const char *mmfileuri, int mp3FrameCnt);
297 } MMFileFunc[MM_FILE_FORMAT_NUM + 1];
298 static int __get_fileformat(const char *urifilename, int *format)
299 {
300         int index;
301         int ret = 0;
302         MMFileIOHandle *fp = NULL;
303
304         debug_error(DEBUG, "%s\n", urifilename);
305
306         ret = mmfile_open(&fp, urifilename, MMFILE_RDONLY);
307
308         if (ret == MMFILE_IO_FAILED) {
309                 debug_error(DEBUG, "error: mmfile_open\n");
310                 if (fp)
311                         mmfile_close(fp);
312                 return MMFILE_FORMAT_FAIL;
313         }
314
315         for (index = 0; index < MM_FILE_FORMAT_NUM; index++) {
316                 debug_msg(RELEASE, "search index = [%d]\n", index);
317
318                 switch (index) {
319                 case MM_FILE_FORMAT_QT:
320                 case MM_FILE_FORMAT_3GP:
321                 case MM_FILE_FORMAT_MP4:
322                         *format = MM_FILE_FORMAT_3GP;
323                         break;
324
325                 case MM_FILE_FORMAT_ASF:
326                 case MM_FILE_FORMAT_WMA:
327                 case MM_FILE_FORMAT_WMV:
328                         *format = MM_FILE_FORMAT_ASF;
329                         break;
330
331                 case MM_FILE_FORMAT_DIVX:
332                 case MM_FILE_FORMAT_AVI:
333                         *format = MM_FILE_FORMAT_AVI;
334                         break;
335
336                 case MM_FILE_FORMAT_MATROSKA:
337                 case MM_FILE_FORMAT_FLV:
338                 case MM_FILE_FORMAT_M2TS:
339                 case MM_FILE_FORMAT_M2PS:
340                 case MM_FILE_FORMAT_REAL:
341                 case MM_FILE_FORMAT_M1AUDIO:
342                 case MM_FILE_FORMAT_M1VIDEO:
343                         *format = index;
344                         break;
345
346                 default: {
347                         *format = MM_FILE_FORMAT_NUM;
348                         debug_error(DEBUG, "error: not supported or invaild format enum[%d]\n", index);
349                         break;
350                 }
351                 }
352
353                 if (MMFileFunc[*format].Valid != NULL && MMFileFunc[*format].Valid(fp, NULL, 0)) {
354                         goto FILE_FORMAT_SUCCESS;
355                 }
356         }
357
358         if (index == MM_FILE_FORMAT_NUM) {
359                 debug_error(DEBUG, "Can't probe file type\n");
360         }
361
362         *format = -1;
363
364         if (fp)
365                 mmfile_close(fp);
366
367         return MMFILE_FORMAT_FAIL;
368
369 FILE_FORMAT_SUCCESS:
370         if (fp)
371                 mmfile_close(fp);
372
373         return MMFILE_FORMAT_SUCCESS;
374 }
375
376 static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
377 {
378         unsigned int i = 0;
379         int len = 0;
380         int ret = MMFILE_FORMAT_SUCCESS;
381         int videoStream = -1;
382         int64_t pos = timestamp;
383         bool find = false;
384         bool first_seek = true;
385         int64_t pts = 0;
386         AVCodecContext *pVideoCodecCtx = NULL;
387         AVCodecParameters *pVideoCodecPar = NULL;
388         AVCodec *pVideoCodec = NULL;
389         AVFrame *pFrame = NULL;
390         AVPacket packet;
391         AVStream *pStream = NULL;
392         double duration = 0;
393         int64_t tmpPts = 0;
394 #ifdef __MMFILE_TEST_MODE__
395         int idx = 0;
396 #endif
397
398         /* Retrieve stream information */
399         if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
400                 debug_error(DEBUG, "error : av_find_stream_info failed");
401                 ret = MMFILE_FORMAT_FAIL;
402                 goto exception; /* Couldn't find stream information */
403         }
404
405         /* Find the first video stream */
406         for (i = 0; i < pFormatCtx->nb_streams; i++) {
407                 if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
408                         videoStream = i;
409                         break;
410                 }
411         }
412
413         if (videoStream == -1) {
414                 debug_error(DEBUG, "error : videoStream == -1");
415                 ret = MMFILE_FORMAT_FAIL;
416                 goto exception; /* Didn't find a video stream */
417         }
418
419         /* Get a pointer to the codec context for the video stream */
420         pVideoCodecPar = pFormatCtx->streams[videoStream]->codecpar;
421         if (pVideoCodecPar == NULL) {
422                 debug_error(DEBUG, "invalid param\n");
423                 ret = MMFILE_FORMAT_FAIL;
424                 goto exception;
425         }
426
427         /* Find the decoder for the video stream */
428         pVideoCodec = avcodec_find_decoder(pVideoCodecPar->codec_id);
429         if (pVideoCodec == NULL) {
430                 debug_error(DEBUG, "error : Unsupported codec");
431                 ret = MMFILE_FORMAT_FAIL;
432                 goto exception; /* Codec not found */
433         }
434
435         pVideoCodecCtx = avcodec_alloc_context3(pVideoCodec);
436         if (NULL == pVideoCodecCtx) {
437                 debug_error(DEBUG, "error: pVideoCodecCtx == NULL\n");
438                 ret = MMFILE_FORMAT_FAIL;
439                 goto exception;
440         }
441
442         ret = avcodec_parameters_to_context(pVideoCodecCtx, pVideoCodecPar);
443         if (ret < 0) {
444                 debug_error(DEBUG, "error: avcodec_parameters_to_context\n");
445                 ret = MMFILE_FORMAT_FAIL;
446                 goto exception;
447         }
448
449         /*set workaround bug flag*/
450         //pVideoCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
451
452         /* Open codec */
453         pVideoCodecCtx->thread_type = 0;
454         pVideoCodecCtx->thread_count = 0;
455         if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) {
456                 debug_error(DEBUG, "error : avcodec_open failed");
457                 ret = MMFILE_FORMAT_FAIL;
458                 goto exception;; /*Could not open codec */
459         }
460
461         /* Storing Data  */
462         /* Allocate video frame */
463         pFrame = av_frame_alloc();
464         if (pFrame == NULL) {
465                 debug_error(DEBUG, "error: pFrame is NULL\n");
466                 ret = MMFILE_FORMAT_FAIL;
467                 goto exception;
468         }
469
470         /* Seeking */
471         pStream = pFormatCtx->streams[videoStream];
472         duration = (double) pFormatCtx->duration / AV_TIME_BASE;
473 #if 0
474         if (duration <= 0) {
475                 double tmpDuration = 0.0;
476
477                 if (pStream->codec->bit_rate > 0 && pFormatCtx->file_size > 0) {
478                         if (pStream->codec->bit_rate >= 8)
479                                 tmpDuration = 0.9 * pFormatCtx->file_size / (pStream->codec->bit_rate / 8);
480
481                         if (tmpDuration > 0)
482                                 duration = tmpDuration;
483                 }
484         }
485 #endif
486         duration = duration * MILLION;
487         if ((duration <= 0) || (duration <= pos)) {
488                 debug_error(DEBUG, "duration error duration[%f] pos[%lld]", duration, pos);
489                 ret = MMFILE_FORMAT_FAIL;
490                 goto exception;
491         }
492
493         if (is_accurate)
494                 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_ANY);
495         else
496                 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
497
498         /* Reading Data */
499
500         av_init_packet(&packet);
501
502         while (av_read_frame(pFormatCtx, &packet) >= 0) {
503
504                 /* Is this a packet from the video stream? */
505                 if (packet.stream_index == videoStream) {
506                         #ifdef __MMFILE_TEST_MODE__
507                         debug_msg(RELEASE, "find Video Stream+++++++[%2d]", idx++);
508                         #endif
509
510                         /* Decode video frame*/
511                         len = avcodec_send_packet(pVideoCodecCtx, &packet);
512                         if (len < 0 && len != AVERROR(EAGAIN) && len != AVERROR_EOF) {
513                                 debug_error(RELEASE, "Error while avcodec_send_packet[%2d]", len);
514                                 break;
515                         }
516
517                         len = avcodec_receive_frame(pVideoCodecCtx, pFrame);
518                         debug_msg(RELEASE, "avcodec_receive_frame[%2d]", len);
519                         if (len < 0 && len != AVERROR(EAGAIN) && len != AVERROR_EOF) {
520                                 debug_warning(DEBUG, "Error while avcodec_receive_frame");
521                         } else if (len >= 0) {
522                                 if ((packet.flags & AV_PKT_FLAG_KEY)) {
523
524                                         if (first_seek || !is_accurate) {
525                                                 /* This is first seeking or not accurate mode.
526                                                 Sometimes flag is AV_PKT_FLAG_KEY but got_picture is NULL.
527                                                 first_seek is used when accurate mode and when time stamp's frame is not key frame.
528                                                 Go back to previousto Key frame and decode frame until time stamp's frame*/
529
530                                                 if (pFrame->key_frame) {
531                                                         debug_msg(RELEASE, "find Video Stream+++++++Find key frame");
532                                                 } else {
533                                                         debug_msg(RELEASE, "find Video Stream+++++++ not key frame");
534                                                 }
535
536                                                 /*eventhough decoded pFrame is not key frame, if packet.flags is AV_PKT_FLAG_KEY then can extract frame*/
537                                                 find = true;
538                                         }
539                                 } else {
540                                         if (is_accurate) {
541                                                 if (first_seek) {
542                                                         pts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
543                                                         first_seek = false;
544
545                                                         av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
546                                                 } else {
547                                                         tmpPts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
548                                                         if (pts == tmpPts)
549                                                                 find = true;
550                                                 }
551                                         }
552                                 }
553                         } else {
554                                 debug_msg(RELEASE, "decode not completed.\n");
555                         }
556
557                         if (find) {
558                                 break;
559                         }
560                 }
561
562                 /* Free the packet that was allocated by av_read_frame*/
563                 av_packet_unref(&packet);
564                 av_init_packet(&packet);
565         }
566
567         /*free pkt after loop breaking*/
568         av_packet_unref(&packet);
569
570         /* Did we get a video frame?*/
571         if (find) {
572
573                 debug_msg(RELEASE, "Find Frame");
574
575                 /* return frame infromations*/
576                 if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
577                         *width = pVideoCodecCtx->coded_width;
578                         *height = pVideoCodecCtx->coded_height;
579                 } else {
580                         *width = pVideoCodecCtx->width;
581                         *height = pVideoCodecCtx->height;
582                 }
583
584                 *size = av_image_get_buffer_size(AV_PIX_FMT_RGB24, *width, *height, 1);
585
586                 if (*size > 0)
587                         *frame = mmfile_malloc(*size);
588
589                 if (NULL == *frame) {
590                         debug_error(DEBUG, "error: avpicture_get_size. [%d]\n", *size);
591                         ret = MMFILE_FORMAT_FAIL;
592                         goto exception;
593                 }
594
595                 debug_msg(RELEASE, "size : %d", *size);
596                 debug_msg(RELEASE, "width : %d", *width);
597                 debug_msg(RELEASE, "height : %d", *height);
598                 debug_msg(RELEASE, "frame : %p", *frame);
599
600                 uint8_t *dst_data[4];
601                 int dst_linesize[4];
602                 ret = av_image_fill_arrays(dst_data, dst_linesize, *frame, AV_PIX_FMT_RGB24, *width, *height, 1);
603                 if (ret < 0) {
604                         debug_error(DEBUG, "error: avpicture_fill fail. errcode = 0x%08X\n", ret);
605                         ret = MMFILE_FORMAT_FAIL;
606                         goto exception;
607                 }
608
609                 struct SwsContext *img_convert_ctx = NULL;
610
611                 img_convert_ctx = sws_getContext(*width, *height, pVideoCodecCtx->pix_fmt, *width, *height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
612
613                 if (NULL == img_convert_ctx) {
614                         debug_error(DEBUG, "failed to get img convet ctx\n");
615                         ret = MMFILE_FORMAT_FAIL;
616                         goto exception;
617                 }
618
619                 ret = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize, 0, *height, dst_data, dst_linesize);
620                 if (ret < 0) {
621                         debug_error(DEBUG, "failed to convet image\n");
622                         sws_freeContext(img_convert_ctx);
623                         img_convert_ctx = NULL;
624                         ret = MMFILE_FORMAT_FAIL;
625                         goto exception;
626                 }
627
628                 sws_freeContext(img_convert_ctx);
629                 img_convert_ctx = NULL;
630
631 #ifdef MMFILE_FORMAT_DEBUG_DUMP
632                 __save_frame(dst_data, dst_linesize, pVideoCodecCtx->width, pVideoCodecCtx->height, (int)(pos / 1000));
633 #endif
634         } else {
635                 debug_error(DEBUG, "Not Found Proper Frame[%d]", find);
636                 ret = MMFILE_FORMAT_FAIL;
637                 goto exception;
638         }
639
640         if (pFrame)                     av_frame_free(&pFrame);
641         if (pVideoCodecCtx)     avcodec_free_context(&pVideoCodecCtx);
642
643         return MMFILE_FORMAT_SUCCESS;
644
645 exception:
646         if (*frame) {
647                 mmfile_free(*frame);
648                 *frame = NULL;
649         }
650         if (pFrame)                     av_frame_free(&pFrame);
651         if (pVideoCodecCtx)     avcodec_free_context(&pVideoCodecCtx);
652
653         return ret;
654 }
655
656 int mmfile_format_get_frame(const char *path, double timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
657 {
658         int ret = MMFILE_FORMAT_SUCCESS;
659         AVFormatContext *pFormatCtx = NULL;
660
661         if (!size || !width || !height) {
662                 return MMFILE_FORMAT_FAIL;
663         }
664
665         av_register_all();
666
667         /* Open video file */
668         if (avformat_open_input(&pFormatCtx, path, NULL, NULL) != 0) {
669                 debug_error(DEBUG, "error : avformat_open_input failed");
670                 return MMFILE_FORMAT_FAIL; /* Couldn't open file */
671         }
672
673         if (!pFormatCtx) {
674                 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.\n");
675                 ret = MMFILE_FORMAT_FAIL;
676                 goto exception;
677         }
678
679         ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
680
681 exception:
682         /* Close video file */
683         if (pFormatCtx) avformat_close_input(&pFormatCtx);
684
685         return ret;
686 }
687
688 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)
689 {
690         int ret = MMFILE_FORMAT_SUCCESS;
691         int format = -1;
692         char mimeType[MMFILE_MIMETYPE_MAX_LEN] = {0, };
693         char ffmpegFormatName[MMFILE_FILE_FMT_MAX_LEN] = {0, };
694         char tempURIBuffer[MMFILE_URI_MAX_LEN] = {0, };
695         char *urifilename = NULL;
696         AVFormatContext *pFormatCtx = NULL;
697         AVInputFormat *grab_iformat = NULL;
698         AVIOContext *pIOCtx = NULL;
699         MMFmemIOHandle *handle = NULL;
700         uint8_t *avio_ctx_buffer = NULL;
701
702         if (!size || !width || !height) {
703                 return MMFILE_FORMAT_FAIL;
704         }
705
706         av_register_all();
707
708         snprintf(tempURIBuffer, MMFILE_URI_MAX_LEN,  "%s%u:%u", MMFILE_MEM_URI, (unsigned int)data, datasize);
709         urifilename = mmfile_strdup(tempURIBuffer);
710         if (!urifilename) {
711                 debug_error(DEBUG, "error: uri is NULL\n");
712                 return MMFILE_FORMAT_FAIL;
713         }
714
715         mmfile_register_io_all();
716
717         ret = __get_fileformat(urifilename, &format);
718         if (ret != MMFILE_FORMAT_SUCCESS) {
719                 debug_error(DEBUG, "error: file format is invalid\n");
720                 return MMFILE_FORMAT_FAIL;
721         }
722
723         if (__getMimeType(format, mimeType, MMFILE_MIMETYPE_MAX_LEN) < 0) {
724                 debug_error(DEBUG, "error: Error in MIME Type finding\n");
725                 return MMFILE_FORMAT_FAIL;
726         }
727
728         memset(ffmpegFormatName, 0x00, MMFILE_FILE_FMT_MAX_LEN);
729
730         ret = mmfile_util_get_ffmpeg_format(mimeType, ffmpegFormatName);
731
732         if (MMFILE_UTIL_SUCCESS != ret) {
733                 debug_error(DEBUG, "error: mmfile_util_get_ffmpeg_format\n");
734                 return MMFILE_FORMAT_FAIL;
735         }
736
737         grab_iformat = av_find_input_format(ffmpegFormatName);
738
739         if (NULL == grab_iformat) {
740                 debug_error(DEBUG, "error: cannot find format\n");
741                 ret = MMFILE_FORMAT_FAIL;
742                 goto exception;
743         }
744
745         avio_ctx_buffer = av_malloc(MMFILE_AVIO_BUFFER_LEN);
746         if (avio_ctx_buffer == NULL) {
747                 debug_error(DEBUG, "error: cannot alloc avio_ctx_buffert\n");
748                 ret = MMFILE_FORMAT_FAIL;
749                 goto exception;
750         }
751
752         ret = _mmf_mem_open(&handle, urifilename);
753         if (ret != MMFILE_IO_SUCCESS) {
754                 debug_warning(DEBUG, "failed to _mmf_mem_open.\n");
755                 av_free(avio_ctx_buffer);
756                 ret = MMFILE_FORMAT_FAIL;
757                 goto exception;
758         }
759
760         pIOCtx = avio_alloc_context(avio_ctx_buffer, MMFILE_AVIO_BUFFER_LEN, 0, handle, _mmf_mem_read, NULL, _mmf_mem_seek);
761         if (pIOCtx == NULL) {
762                 debug_error(DEBUG, "error: cannot alloc io context\n");
763                 av_free(avio_ctx_buffer);
764                 mmfile_free(handle);
765                 ret = MMFILE_FORMAT_FAIL;
766                 goto exception;
767         }
768
769         pFormatCtx = avformat_alloc_context();
770         if (!pFormatCtx) {
771                 debug_warning(DEBUG, "failed to avformat_alloc_context\n");
772                 ret = MMFILE_FORMAT_FAIL;
773                 goto exception;
774         }
775
776         pFormatCtx->pb = pIOCtx;
777
778         ret = avformat_open_input(&pFormatCtx, "", grab_iformat, NULL);
779         if (ret < 0) {
780                 debug_error(DEBUG, "error: cannot open %s %d\n", urifilename, ret);
781                 goto exception;
782         }
783
784         ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
785
786 exception:
787         /* Close video file */
788         if (pIOCtx) {
789                         av_free(pIOCtx->buffer);
790                         av_free(pIOCtx->opaque);
791                         av_free(pIOCtx);
792         }
793
794         if (pFormatCtx)
795                 avformat_close_input(&pFormatCtx);
796
797         return ret;
798 }