4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Haejeong Kim <backto.kim@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 #include <libavformat/avformat.h>
23 #include <libavcodec/avcodec.h>
24 #include <libswscale/swscale.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"
33 #define MILLION 1000000
34 #ifdef MMFILE_FORMAT_DEBUG_DUMP
35 static void __save_frame(AVFrame *pFrame, int width, int height, int iFrame);
37 void __save_frame(AVFrame *pFrame, int width, int height, int iFrame)
43 sprintf(szFilename, "frame%d.ppm", iFrame);
44 pFile = fopen(szFilename, "wb");
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);
59 static int __getMimeType(int formatId, char *mimeType, int buf_size)
61 int ret = 0; /*default: success*/
64 case MM_FILE_FORMAT_3GP:
65 case MM_FILE_FORMAT_MP4:
66 snprintf(mimeType, buf_size, "video/3gpp");
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");
73 case MM_FILE_FORMAT_AVI:
74 snprintf(mimeType, buf_size, "video/avi");
76 case MM_FILE_FORMAT_OGG:
77 snprintf(mimeType, buf_size, "video/ogg");
79 case MM_FILE_FORMAT_REAL:
80 snprintf(mimeType, buf_size, "video/vnd.rn-realmedia");
82 case MM_FILE_FORMAT_AMR:
83 snprintf(mimeType, buf_size, "audio/AMR");
85 case MM_FILE_FORMAT_AAC:
86 snprintf(mimeType, buf_size, "audio/aac");
88 case MM_FILE_FORMAT_MP3:
89 snprintf(mimeType, buf_size, "audio/mp3");
91 case MM_FILE_FORMAT_AIFF:
92 case MM_FILE_FORMAT_WAV:
93 snprintf(mimeType, buf_size, "audio/wave");
95 case MM_FILE_FORMAT_MID:
96 snprintf(mimeType, buf_size, "audio/midi");
98 case MM_FILE_FORMAT_MMF:
99 snprintf(mimeType, buf_size, "audio/mmf");
101 case MM_FILE_FORMAT_DIVX:
102 snprintf(mimeType, buf_size, "video/divx");
104 case MM_FILE_FORMAT_IMELODY:
105 snprintf(mimeType, buf_size, "audio/iMelody");
107 case MM_FILE_FORMAT_JPG:
108 snprintf(mimeType, buf_size, "image/jpeg");
110 case MM_FILE_FORMAT_AU:
111 snprintf(mimeType, buf_size, "audio/basic");
113 case MM_FILE_FORMAT_VOB:
114 snprintf(mimeType, buf_size, "video/dvd");
116 case MM_FILE_FORMAT_FLV:
117 snprintf(mimeType, buf_size, "video/x-flv");
119 case MM_FILE_FORMAT_QT:
120 snprintf(mimeType, buf_size, "video/quicktime");
122 case MM_FILE_FORMAT_MATROSKA:
123 snprintf(mimeType, buf_size, "video/x-matroska");
125 case MM_FILE_FORMAT_FLAC:
126 snprintf(mimeType, buf_size, "audio/x-flac");
128 case MM_FILE_FORMAT_M2TS:
129 snprintf(mimeType, buf_size, "video/MP2T");
131 case MM_FILE_FORMAT_M2PS:
132 snprintf(mimeType, buf_size, "video/MP2P");
134 case MM_FILE_FORMAT_M1VIDEO:
135 snprintf(mimeType, buf_size, "video/mpeg");
137 case MM_FILE_FORMAT_M1AUDIO:
138 snprintf(mimeType, buf_size, "audio/x-mpegaudio");
145 debug_msg(RELEASE, "id: %d, mimetype: %s\n", formatId, mimeType);
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)
158 MMFileIOHandle *fp = NULL;
160 debug_error(DEBUG, "%s\n", urifilename);
162 ret = mmfile_open(&fp, urifilename, MMFILE_RDONLY);
164 if (ret == MMFILE_IO_FAILED) {
165 debug_error(DEBUG, "error: mmfile_open\n");
168 return MMFILE_FORMAT_FAIL;
171 for (index = 0; index < MM_FILE_FORMAT_NUM; index++) {
172 debug_msg(RELEASE, "search index = [%d]\n", 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;
181 case MM_FILE_FORMAT_ASF:
182 case MM_FILE_FORMAT_WMA:
183 case MM_FILE_FORMAT_WMV:
184 *format = MM_FILE_FORMAT_ASF;
187 case MM_FILE_FORMAT_DIVX:
188 case MM_FILE_FORMAT_AVI:
189 *format = MM_FILE_FORMAT_AVI;
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:
203 *format = MM_FILE_FORMAT_NUM;
204 debug_error(DEBUG, "error: not supported or invaild format enum[%d]\n", index);
209 if (MMFileFunc[*format].Valid!= NULL && MMFileFunc[*format].Valid(fp, NULL, 0)) {
210 goto FILE_FORMAT_SUCCESS;
214 if (index == MM_FILE_FORMAT_NUM) {
215 debug_error(DEBUG, "Can't probe file type\n");
223 return MMFILE_FORMAT_FAIL;
229 return MMFILE_FORMAT_SUCCESS;
232 static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
237 int ret = MMFILE_FORMAT_SUCCESS;
238 int videoStream = -1;
239 int key_detected = 0;
241 int64_t pos = timestamp;
243 bool first_seek = true;
245 AVCodecContext *pVideoCodecCtx = NULL;
246 AVCodec *pVideoCodec = NULL;
247 AVFrame *pFrame = NULL, *pFrameRGB = NULL;
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 */
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) {
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 */
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;
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 */
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 */
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;
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;
314 AVStream *pStream = pFormatCtx->streams[videoStream];
315 double duration = (double) pFormatCtx->duration / AV_TIME_BASE;
318 double tmpDuration = 0.0;
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);
325 duration = tmpDuration;
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;
337 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_ANY);
339 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
343 #ifdef __MMFILE_TEST_MODE__
347 av_init_packet(&packet);
349 while (av_read_frame(pFormatCtx, &packet) >= 0) {
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++);
358 /* Decode video frame*/
359 len = avcodec_decode_video2(pVideoCodecCtx, pFrame, &got_picture, &packet);
361 debug_warning(DEBUG, "Error while decoding frame");
362 } else if ((packet.flags & AV_PKT_FLAG_KEY) || (key_detected == 1)) {
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*/
373 if (pFrame->key_frame) {
374 debug_msg(RELEASE, "find Video Stream+++++++Find key frame");
376 debug_msg(RELEASE, "find Video Stream+++++++ not key frame");
379 /*eventhough decoded pFrame is not key frame, if packet.flags is AV_PKT_FLAG_KEY then can extract frame*/
383 debug_msg(RELEASE, "find Video Stream+++++++Find key but no frame");
390 pts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
393 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
395 tmpPts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
402 if (find && got_picture) {
407 /* Free the packet that was allocated by av_read_frame*/
408 av_free_packet(&packet);
409 av_init_packet(&packet);
412 /*free pkt after loop breaking*/
413 av_free_packet(&packet);
415 /* Did we get a video frame?*/
416 if (got_picture && find) {
418 debug_msg(RELEASE, "Find Frame");
420 /* return frame infromations*/
421 if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
422 *width = pVideoCodecCtx->coded_width;
423 *height = pVideoCodecCtx->coded_height;
425 *width = pVideoCodecCtx->width;
426 *height = pVideoCodecCtx->height;
429 *size = avpicture_get_size(AV_PIX_FMT_RGB24, *width, *height);
432 *frame = mmfile_malloc(*size);
434 if (NULL == *frame) {
435 debug_error(DEBUG, "error: avpicture_get_size. [%d]\n", *size);
436 ret = MMFILE_FORMAT_FAIL;
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);
445 ret = avpicture_fill((AVPicture *)pFrameRGB, *frame, AV_PIX_FMT_RGB24, *width, *height);
447 debug_error(DEBUG, "error: avpicture_fill fail. errcode = 0x%08X\n", ret);
448 ret = MMFILE_FORMAT_FAIL;
452 struct SwsContext *img_convert_ctx = NULL;
454 img_convert_ctx = sws_getContext(*width, *height, pVideoCodecCtx->pix_fmt,
455 *width, *height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
457 if (NULL == img_convert_ctx) {
458 debug_error(DEBUG, "failed to get img convet ctx\n");
459 ret = MMFILE_FORMAT_FAIL;
463 ret = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize,
464 0, *height, pFrameRGB->data, pFrameRGB->linesize);
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;
473 sws_freeContext(img_convert_ctx);
474 img_convert_ctx = NULL;
476 #ifdef MMFILE_FORMAT_DEBUG_DUMP
477 __save_frame(pFrameRGB, pVideoCodecCtx->width, pVideoCodecCtx->height, (int)(pos / 1000));
480 debug_error(DEBUG, "Not Found Proper Frame[%d][%d]", got_picture, find);
481 ret = MMFILE_FORMAT_FAIL;
485 if (pFrame) av_free(pFrame);
486 if (pFrameRGB) av_free(pFrameRGB);
487 if (pVideoCodecCtx) avcodec_close(pVideoCodecCtx);
489 return MMFILE_FORMAT_SUCCESS;
496 if (pFrame) av_free(pFrame);
497 if (pFrameRGB) av_free(pFrameRGB);
498 if (pVideoCodecCtx) avcodec_close(pVideoCodecCtx);
503 int mmfile_format_get_frame(const char *path, double timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
505 int ret = MMFILE_FORMAT_SUCCESS;
506 AVFormatContext *pFormatCtx = NULL;
508 if (!size || !width || !height) {
509 return MMFILE_FORMAT_FAIL;
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 */
521 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.\n");
522 ret = MMFILE_FORMAT_FAIL;
526 ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
529 /* Close video file */
530 if (pFormatCtx) avformat_close_input(&pFormatCtx);
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)
537 int ret = MMFILE_FORMAT_SUCCESS;
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;
546 if (!size || !width || !height) {
547 return MMFILE_FORMAT_FAIL;
552 snprintf(tempURIBuffer, MMFILE_URI_MAX_LEN, "%s%u:%u", MMFILE_MEM_URI, (unsigned int)data, datasize);
553 urifilename = mmfile_strdup(tempURIBuffer);
555 debug_error(DEBUG, "error: uri is NULL\n");
556 return MMFILE_FORMAT_FAIL;
559 mmfile_register_io_all();
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;
567 ffurl_register_protocol(&MMFileMEMProtocol);
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;
574 memset(ffmpegFormatName, 0x00, MMFILE_FILE_FMT_MAX_LEN);
576 ret = mmfile_util_get_ffmpeg_format(mimeType, ffmpegFormatName);
578 if (MMFILE_UTIL_SUCCESS != ret) {
579 debug_error(DEBUG, "error: mmfile_util_get_ffmpeg_format\n");
580 return MMFILE_FORMAT_FAIL;
583 grab_iformat = av_find_input_format(ffmpegFormatName);
585 if (NULL == grab_iformat) {
586 debug_error(DEBUG, "error: cannot find format\n");
590 ret = avformat_open_input(&pFormatCtx, urifilename, grab_iformat, NULL);
592 debug_error(DEBUG, "error: cannot open %s %d\n", urifilename, ret);
597 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.\n");
598 ret = MMFILE_FORMAT_FAIL;
602 ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
605 /* Close video file */
606 if (pFormatCtx) avformat_close_input(&pFormatCtx);
608 ffurl_deregister_protocol(&MMFileMEMProtocol);