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_frame.h"
32 #define MILLION 1000000
33 #ifdef MMFILE_FORMAT_DEBUG_DUMP
34 static void __save_frame(AVFrame *pFrame, int width, int height, int iFrame);
36 void __save_frame(AVFrame *pFrame, int width, int height, int iFrame)
39 char szFilename[32] = {0,};
43 memset(szFilename, 0x00, sizeof(szFilename));
44 snprintf(szFilename, sizeof(szFilename), "frame%d.ppm", iFrame);
45 pFile = fopen(szFilename, "wb");
50 fprintf(pFile, "P6\n%d %d\n255\n", width, height);
51 /* Write pixel data */
52 for (y = 0; y < height; y++)
53 fwrite(pFrame->data[0] + y * pFrame->linesize[0], 1, width * 3, pFile);
60 static int _mmf_mem_read(void *opaque, uint8_t *buf, int size);
61 static int64_t _mmf_mem_seek(void *opaque, int64_t pos, int whence);
70 static int _mmf_mem_open(MMFmemIOHandle **handle, const char *filename)
72 MMFmemIOHandle *memHandle = NULL;
73 char **splitedString = NULL;
75 filename += strlen(MMFILE_MEM_URI);
77 splitedString = mmfile_strsplit(filename, ":");
78 if (splitedString == NULL) {
79 debug_error(DEBUG, "invalid param\n");
80 return MMFILE_IO_FAILED;
83 if (!splitedString[0] || !splitedString[1]) {
84 debug_error(DEBUG, "invalid param\n");
88 memHandle = mmfile_malloc(sizeof(MMFmemIOHandle));
90 debug_error(DEBUG, "error: mmfile_malloc memHandle\n");
94 memHandle->ptr = (unsigned char *)atoll(splitedString[0]); /*memory allocation address changed. memHandle->ptr = (unsigned char*)atoi(splitedString[0]); */
95 memHandle->size = atoi(splitedString[1]);
96 memHandle->offset = 0;
102 mmfile_strfreev(splitedString);
105 return MMFILE_IO_SUCCESS;
110 mmfile_strfreev(splitedString);
113 return MMFILE_IO_FAILED;
116 static int _mmf_mem_read(void *opaque, uint8_t *buf, int size)
118 MMFmemIOHandle *memHandle = NULL;
119 const unsigned char *c = NULL;
122 if (!opaque || !buf) {
123 debug_error(DEBUG, "invalid para\n");
124 return MMFILE_UTIL_FAIL;
129 if (!memHandle->ptr) {
130 debug_error(DEBUG, "invalid para\n");
131 return MMFILE_UTIL_FAIL;
134 if (memHandle->offset >= memHandle->size) {
135 /* for some file formats last file read */
136 debug_error(DEBUG, "File Read is beyond the file Size\n");
137 return MMFILE_UTIL_FAIL;
141 c = memHandle->ptr + memHandle->offset;
143 if (memHandle->state != EOF) {
145 if (len + memHandle->offset > memHandle->size) {
146 len = memHandle->size - memHandle->offset;
152 memHandle->offset += len;
154 if (memHandle->offset == memHandle->size) {
155 memHandle->state = EOF;
161 static int64_t _mmf_mem_seek(void *opaque, int64_t pos, int whence)
163 MMFmemIOHandle *memHandle = NULL;
164 long long tmp_offset = 0;
167 debug_error(DEBUG, "invalid para\n");
168 return MMFILE_UTIL_FAIL;
175 tmp_offset = 0 + pos;
178 tmp_offset = memHandle->offset + pos;
181 tmp_offset = memHandle->size + pos;
183 case AVSEEK_SIZE: /*FFMPEG specific*/
184 return memHandle->size;
186 return MMFILE_UTIL_FAIL;
190 if (tmp_offset < 0 && tmp_offset > memHandle->size) {
191 debug_error(DEBUG, "invalid file offset\n");
192 return MMFILE_UTIL_FAIL;
196 memHandle->state = (tmp_offset >= memHandle->size) ? EOF : !EOF;
197 memHandle->offset = (unsigned int) tmp_offset;
202 static int __getMimeType(int formatId, char *mimeType, int buf_size)
204 int ret = 0; /*default: success*/
207 case MM_FILE_FORMAT_3GP:
208 case MM_FILE_FORMAT_MP4:
209 snprintf(mimeType, buf_size, "video/3gpp");
211 case MM_FILE_FORMAT_ASF:
212 case MM_FILE_FORMAT_WMA:
213 case MM_FILE_FORMAT_WMV:
214 snprintf(mimeType, buf_size, "video/x-ms-asf");
216 case MM_FILE_FORMAT_AVI:
217 snprintf(mimeType, buf_size, "video/avi");
219 case MM_FILE_FORMAT_OGG:
220 snprintf(mimeType, buf_size, "video/ogg");
222 case MM_FILE_FORMAT_REAL:
223 snprintf(mimeType, buf_size, "video/vnd.rn-realmedia");
225 case MM_FILE_FORMAT_AMR:
226 snprintf(mimeType, buf_size, "audio/AMR");
228 case MM_FILE_FORMAT_AAC:
229 snprintf(mimeType, buf_size, "audio/aac");
231 case MM_FILE_FORMAT_MP3:
232 snprintf(mimeType, buf_size, "audio/mp3");
234 case MM_FILE_FORMAT_AIFF:
235 case MM_FILE_FORMAT_WAV:
236 snprintf(mimeType, buf_size, "audio/wave");
238 case MM_FILE_FORMAT_MID:
239 snprintf(mimeType, buf_size, "audio/midi");
241 case MM_FILE_FORMAT_MMF:
242 snprintf(mimeType, buf_size, "audio/mmf");
244 case MM_FILE_FORMAT_DIVX:
245 snprintf(mimeType, buf_size, "video/divx");
247 case MM_FILE_FORMAT_IMELODY:
248 snprintf(mimeType, buf_size, "audio/iMelody");
250 case MM_FILE_FORMAT_JPG:
251 snprintf(mimeType, buf_size, "image/jpeg");
253 case MM_FILE_FORMAT_AU:
254 snprintf(mimeType, buf_size, "audio/basic");
256 case MM_FILE_FORMAT_VOB:
257 snprintf(mimeType, buf_size, "video/dvd");
259 case MM_FILE_FORMAT_FLV:
260 snprintf(mimeType, buf_size, "video/x-flv");
262 case MM_FILE_FORMAT_QT:
263 snprintf(mimeType, buf_size, "video/quicktime");
265 case MM_FILE_FORMAT_MATROSKA:
266 snprintf(mimeType, buf_size, "video/x-matroska");
268 case MM_FILE_FORMAT_FLAC:
269 snprintf(mimeType, buf_size, "audio/x-flac");
271 case MM_FILE_FORMAT_M2TS:
272 snprintf(mimeType, buf_size, "video/MP2T");
274 case MM_FILE_FORMAT_M2PS:
275 snprintf(mimeType, buf_size, "video/MP2P");
277 case MM_FILE_FORMAT_M1VIDEO:
278 snprintf(mimeType, buf_size, "video/mpeg");
280 case MM_FILE_FORMAT_M1AUDIO:
281 snprintf(mimeType, buf_size, "audio/x-mpegaudio");
288 debug_msg(RELEASE, "id: %d, mimetype: %s\n", formatId, mimeType);
293 extern const struct {
294 int (*Open)(MMFileFormatContext *fileContext);
295 int (*Valid)(MMFileIOHandle *pFileIO, const char *mmfileuri, int mp3FrameCnt);
296 } MMFileFunc[MM_FILE_FORMAT_NUM + 1];
297 static int __get_fileformat(const char *urifilename, int *format)
301 MMFileIOHandle *fp = NULL;
303 debug_error(DEBUG, "%s\n", urifilename);
305 ret = mmfile_open(&fp, urifilename, MMFILE_RDONLY);
307 if (ret == MMFILE_IO_FAILED) {
308 debug_error(DEBUG, "error: mmfile_open\n");
311 return MMFILE_FORMAT_FAIL;
314 for (index = 0; index < MM_FILE_FORMAT_NUM; index++) {
315 debug_msg(RELEASE, "search index = [%d]\n", index);
318 case MM_FILE_FORMAT_QT:
319 case MM_FILE_FORMAT_3GP:
320 case MM_FILE_FORMAT_MP4:
321 *format = MM_FILE_FORMAT_3GP;
324 case MM_FILE_FORMAT_ASF:
325 case MM_FILE_FORMAT_WMA:
326 case MM_FILE_FORMAT_WMV:
327 *format = MM_FILE_FORMAT_ASF;
330 case MM_FILE_FORMAT_DIVX:
331 case MM_FILE_FORMAT_AVI:
332 *format = MM_FILE_FORMAT_AVI;
335 case MM_FILE_FORMAT_MATROSKA:
336 case MM_FILE_FORMAT_FLV:
337 case MM_FILE_FORMAT_M2TS:
338 case MM_FILE_FORMAT_M2PS:
339 case MM_FILE_FORMAT_REAL:
340 case MM_FILE_FORMAT_M1AUDIO:
341 case MM_FILE_FORMAT_M1VIDEO:
346 *format = MM_FILE_FORMAT_NUM;
347 debug_error(DEBUG, "error: not supported or invaild format enum[%d]\n", index);
352 if (MMFileFunc[*format].Valid!= NULL && MMFileFunc[*format].Valid(fp, NULL, 0)) {
353 goto FILE_FORMAT_SUCCESS;
357 if (index == MM_FILE_FORMAT_NUM) {
358 debug_error(DEBUG, "Can't probe file type\n");
366 return MMFILE_FORMAT_FAIL;
372 return MMFILE_FORMAT_SUCCESS;
375 static int __mmfile_get_frame(AVFormatContext *pFormatCtx, int64_t timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
379 int ret = MMFILE_FORMAT_SUCCESS;
380 int videoStream = -1;
381 int key_detected = 0;
383 int64_t pos = timestamp;
385 bool first_seek = true;
387 AVCodecContext *pVideoCodecCtx = NULL;
388 AVCodec *pVideoCodec = NULL;
389 AVFrame *pFrame = NULL, *pFrameRGB = NULL;
392 /* Retrieve stream information */
393 if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
394 debug_error(DEBUG, "error : av_find_stream_info failed");
395 ret = MMFILE_FORMAT_FAIL;
396 goto exception; /* Couldn't find stream information */
399 /* Find the first video stream */
400 for (i = 0; i < pFormatCtx->nb_streams; i++) {
401 if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
407 if (videoStream == -1) {
408 debug_error(DEBUG, "error : videoStream == -1");
409 ret = MMFILE_FORMAT_FAIL;
410 goto exception; /* Didn't find a video stream */
413 /* Get a pointer to the codec context for the video stream */
414 pVideoCodecCtx = pFormatCtx->streams[videoStream]->codec;
415 if (pVideoCodecCtx == NULL) {
416 debug_error(DEBUG, "invalid param\n");
417 ret = MMFILE_FORMAT_FAIL;
421 /* Find the decoder for the video stream */
422 pVideoCodec = avcodec_find_decoder(pVideoCodecCtx->codec_id);
423 if (pVideoCodec == NULL) {
424 debug_error(DEBUG, "error : Unsupported codec");
425 ret = MMFILE_FORMAT_FAIL;
426 goto exception; /* Codec not found */
430 pVideoCodecCtx->thread_type = 0;
431 pVideoCodecCtx->thread_count = 0;
432 if (avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) {
433 debug_error(DEBUG, "error : avcodec_open failed");
434 ret = MMFILE_FORMAT_FAIL;
435 goto exception;; /*Could not open codec */
439 /* Allocate video frame */
440 pFrame = av_frame_alloc();
441 if (pFrame == NULL) {
442 debug_error(DEBUG, "error: pFrame is NULL\n");
443 ret = MMFILE_FORMAT_FAIL;
447 /* Allocate an AVFrame structure */
448 pFrameRGB = av_frame_alloc();
449 if (pFrameRGB == NULL) {
450 debug_error(DEBUG, "error: pFrameRGB is NULL\n");
451 ret = MMFILE_FORMAT_FAIL;
456 AVStream *pStream = pFormatCtx->streams[videoStream];
457 double duration = (double) pFormatCtx->duration / AV_TIME_BASE;
460 double tmpDuration = 0.0;
462 if (pStream->codec->bit_rate > 0 && pFormatCtx->file_size > 0) {
463 if (pStream->codec->bit_rate >= 8)
464 tmpDuration = 0.9 * pFormatCtx->file_size / (pStream->codec->bit_rate / 8);
467 duration = tmpDuration;
471 duration = duration * MILLION;
472 if ((duration <= 0) || (duration <= pos)) {
473 debug_error(DEBUG, "duration error duration[%f] pos[%lld]", duration, pos);
474 ret = MMFILE_FORMAT_FAIL;
479 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_ANY);
481 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
485 #ifdef __MMFILE_TEST_MODE__
489 av_init_packet(&packet);
491 while (av_read_frame(pFormatCtx, &packet) >= 0) {
494 /* Is this a packet from the video stream? */
495 if (packet.stream_index == videoStream) {
496 #ifdef __MMFILE_TEST_MODE__
497 debug_msg(RELEASE, "find Video Stream+++++++[%2d]", idx++);
500 /* Decode video frame*/
501 len = avcodec_decode_video2(pVideoCodecCtx, pFrame, &got_picture, &packet);
503 debug_warning(DEBUG, "Error while decoding frame");
504 } else if ((packet.flags & AV_PKT_FLAG_KEY) || (key_detected == 1)) {
508 if (first_seek || !is_accurate) {
509 /* This is first seeking or not accurate mode.
510 Sometimes flag is AV_PKT_FLAG_KEY but got_picture is NULL.
511 first_seek is used when accurate mode and when time stamp's frame is not key frame.
512 Go back to previousto Key frame and decode frame until time stamp's frame*/
515 if (pFrame->key_frame) {
516 debug_msg(RELEASE, "find Video Stream+++++++Find key frame");
518 debug_msg(RELEASE, "find Video Stream+++++++ not key frame");
521 /*eventhough decoded pFrame is not key frame, if packet.flags is AV_PKT_FLAG_KEY then can extract frame*/
525 debug_msg(RELEASE, "find Video Stream+++++++Find key but no frame");
532 pts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
535 av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
537 tmpPts = (packet.pts == (int64_t)AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
544 if (find && got_picture) {
549 /* Free the packet that was allocated by av_read_frame*/
550 av_free_packet(&packet);
551 av_init_packet(&packet);
554 /*free pkt after loop breaking*/
555 av_free_packet(&packet);
557 /* Did we get a video frame?*/
558 if (got_picture && find) {
560 debug_msg(RELEASE, "Find Frame");
562 /* return frame infromations*/
563 if ((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
564 *width = pVideoCodecCtx->coded_width;
565 *height = pVideoCodecCtx->coded_height;
567 *width = pVideoCodecCtx->width;
568 *height = pVideoCodecCtx->height;
571 *size = avpicture_get_size(AV_PIX_FMT_RGB24, *width, *height);
574 *frame = mmfile_malloc(*size);
576 if (NULL == *frame) {
577 debug_error(DEBUG, "error: avpicture_get_size. [%d]\n", *size);
578 ret = MMFILE_FORMAT_FAIL;
582 debug_msg(RELEASE, "size : %d", *size);
583 debug_msg(RELEASE, "width : %d", *width);
584 debug_msg(RELEASE, "height : %d", *height);
585 debug_msg(RELEASE, "frame : %p", *frame);
587 ret = avpicture_fill((AVPicture *)pFrameRGB, *frame, AV_PIX_FMT_RGB24, *width, *height);
589 debug_error(DEBUG, "error: avpicture_fill fail. errcode = 0x%08X\n", ret);
590 ret = MMFILE_FORMAT_FAIL;
594 struct SwsContext *img_convert_ctx = NULL;
596 img_convert_ctx = sws_getContext(*width, *height, pVideoCodecCtx->pix_fmt,
597 *width, *height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
599 if (NULL == img_convert_ctx) {
600 debug_error(DEBUG, "failed to get img convet ctx\n");
601 ret = MMFILE_FORMAT_FAIL;
605 ret = sws_scale(img_convert_ctx, (const uint8_t * const *)pFrame->data, pFrame->linesize,
606 0, *height, pFrameRGB->data, pFrameRGB->linesize);
608 debug_error(DEBUG, "failed to convet image\n");
609 sws_freeContext(img_convert_ctx);
610 img_convert_ctx = NULL;
611 ret = MMFILE_FORMAT_FAIL;
615 sws_freeContext(img_convert_ctx);
616 img_convert_ctx = NULL;
618 #ifdef MMFILE_FORMAT_DEBUG_DUMP
619 __save_frame(pFrameRGB, pVideoCodecCtx->width, pVideoCodecCtx->height, (int)(pos / 1000));
622 debug_error(DEBUG, "Not Found Proper Frame[%d][%d]", got_picture, find);
623 ret = MMFILE_FORMAT_FAIL;
627 if (pFrame) av_free(pFrame);
628 if (pFrameRGB) av_free(pFrameRGB);
629 if (pVideoCodecCtx) avcodec_close(pVideoCodecCtx);
631 return MMFILE_FORMAT_SUCCESS;
638 if (pFrame) av_free(pFrame);
639 if (pFrameRGB) av_free(pFrameRGB);
640 if (pVideoCodecCtx) avcodec_close(pVideoCodecCtx);
645 int mmfile_format_get_frame(const char *path, double timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
647 int ret = MMFILE_FORMAT_SUCCESS;
648 AVFormatContext *pFormatCtx = NULL;
650 if (!size || !width || !height) {
651 return MMFILE_FORMAT_FAIL;
656 /* Open video file */
657 if (avformat_open_input(&pFormatCtx, path, NULL, NULL) != 0) {
658 debug_error(DEBUG, "error : avformat_open_input failed");
659 return MMFILE_FORMAT_FAIL; /* Couldn't open file */
663 debug_warning(DEBUG, "failed to find av stream. maybe corrupted data.\n");
664 ret = MMFILE_FORMAT_FAIL;
668 ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
671 /* Close video file */
672 if (pFormatCtx) avformat_close_input(&pFormatCtx);
677 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)
679 int ret = MMFILE_FORMAT_SUCCESS;
681 char mimeType[MMFILE_MIMETYPE_MAX_LEN] = {0, };
682 char ffmpegFormatName[MMFILE_FILE_FMT_MAX_LEN] = {0, };
683 char tempURIBuffer[MMFILE_URI_MAX_LEN] = {0, };
684 char *urifilename = NULL;
685 AVFormatContext *pFormatCtx = NULL;
686 AVInputFormat *grab_iformat = NULL;
687 AVIOContext *pIOCtx = NULL;
688 MMFmemIOHandle *handle = NULL;
689 uint8_t *avio_ctx_buffer = NULL;
691 if (!size || !width || !height) {
692 return MMFILE_FORMAT_FAIL;
697 snprintf(tempURIBuffer, MMFILE_URI_MAX_LEN, "%s%u:%u", MMFILE_MEM_URI, (unsigned int)data, datasize);
698 urifilename = mmfile_strdup(tempURIBuffer);
700 debug_error(DEBUG, "error: uri is NULL\n");
701 return MMFILE_FORMAT_FAIL;
704 mmfile_register_io_all();
706 ret = __get_fileformat(urifilename, &format);
707 if (ret != MMFILE_FORMAT_SUCCESS) {
708 debug_error(DEBUG, "error: file format is invalid\n");
709 return MMFILE_FORMAT_FAIL;
712 if (__getMimeType(format, mimeType, MMFILE_MIMETYPE_MAX_LEN) < 0) {
713 debug_error(DEBUG, "error: Error in MIME Type finding\n");
714 return MMFILE_FORMAT_FAIL;
717 memset(ffmpegFormatName, 0x00, MMFILE_FILE_FMT_MAX_LEN);
719 ret = mmfile_util_get_ffmpeg_format(mimeType, ffmpegFormatName);
721 if (MMFILE_UTIL_SUCCESS != ret) {
722 debug_error(DEBUG, "error: mmfile_util_get_ffmpeg_format\n");
723 return MMFILE_FORMAT_FAIL;
726 grab_iformat = av_find_input_format(ffmpegFormatName);
728 if (NULL == grab_iformat) {
729 debug_error(DEBUG, "error: cannot find format\n");
730 ret = MMFILE_FORMAT_FAIL;
734 avio_ctx_buffer = av_malloc(MMFILE_AVIO_BUFFER_LEN);
735 if (avio_ctx_buffer == NULL) {
736 debug_error(DEBUG, "error: cannot alloc avio_ctx_buffert\n");
737 ret = MMFILE_FORMAT_FAIL;
741 ret = _mmf_mem_open(&handle, urifilename);
742 if (ret !=MMFILE_IO_SUCCESS) {
743 debug_warning(DEBUG, "failed to _mmf_mem_open.\n");
744 av_free(avio_ctx_buffer);
745 ret = MMFILE_FORMAT_FAIL;
749 pIOCtx = avio_alloc_context(avio_ctx_buffer, MMFILE_AVIO_BUFFER_LEN, 0, handle, _mmf_mem_read, NULL, _mmf_mem_seek);
750 if (pIOCtx == NULL) {
751 debug_error(DEBUG, "error: cannot alloc io context\n");
752 av_free(avio_ctx_buffer);
754 ret = MMFILE_FORMAT_FAIL;
758 pFormatCtx = avformat_alloc_context();
760 debug_warning(DEBUG, "failed to avformat_alloc_context\n");
761 ret = MMFILE_FORMAT_FAIL;
765 pFormatCtx->pb = pIOCtx;
767 ret = avformat_open_input(&pFormatCtx, "", grab_iformat, NULL);
769 debug_error(DEBUG, "error: cannot open %s %d\n", urifilename, ret);
773 ret = __mmfile_get_frame(pFormatCtx, timestamp, is_accurate, frame, size, width, height);
776 /* Close video file */
778 av_free(pIOCtx->buffer);
779 av_free(pIOCtx->opaque);
784 avformat_close_input(&pFormatCtx);