2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
18 #include <FBaseColArrayListT.h>
19 #include <FBaseColHashMap.h>
20 #include <FBaseInteger.h>
21 #include <FMediaTypes.h>
22 #include <FBaseSysLog.h>
23 #include "FMedia_Ffmpeg.h"
24 #include "FMedia_IVideoDecoder.h"
25 #include "FMedia_H264Decoder.h"
27 using namespace Tizen::Base;
28 using namespace Tizen::Io;
29 using namespace Tizen::Base::Collection;
31 namespace Tizen { namespace Media
34 static const int _INPUT_BUFFER_PADDING_SIZE = 8;
35 static const int _ERROR_STRING_LENGTH = 256;
38 _H264Decoder_CreateInstance(void)
40 return new (std::nothrow) _H264Decoder();
43 _H264Decoder::_H264Decoder(void)
47 __decodeCalled = false;
49 __inPacketMode = false;
52 _H264Decoder::~_H264Decoder(void)
54 if (__pCodecCtx != null)
56 avcodec_flush_buffers(__pCodecCtx);
57 avcodec_close(__pCodecCtx);
59 av_parser_close(__pParser);
66 _H264Decoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
70 IMapEnumerator* pMapEnum = null;
72 Integer* pValue = null;
76 SysAssertf((__pCodecCtx == null && __pCodec == null), " Already Constructed .");
\r
80 // The initialization values are given in the Hashmap
81 pMapEnum = pOption->GetMapEnumeratorN();
84 while (pMapEnum->MoveNext() == E_SUCCESS)
86 pKey = dynamic_cast<Integer*>(pMapEnum->GetKey());
87 pValue = dynamic_cast<Integer*>(pMapEnum->GetValue());
92 value = pValue->ToInt();
95 case MEDIA_PROPERTY_VIDEO_H264_USE_ANNEX_B:
96 SysTryCatch(NID_MEDIA, value == 0 || value == 1,
97 r = E_OUT_OF_RANGE, E_OUT_OF_RANGE,
98 "[%s] Invalid argument is used. The value is out of range", GetErrorMessage(E_OUT_OF_RANGE));
\r
112 avcodec_register_all();
114 __pCodecCtx = avcodec_alloc_context();
115 SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM, "[%s] AVCODEC Context Allcoation Failed", GetErrorMessage(E_SYSTEM));
\r
116 __pCodec = avcodec_find_decoder(CODEC_ID_H264);
117 SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM, "[%s] AVCODEC Find Decoder Failed for CODEC_ID_H264", GetErrorMessage(E_SYSTEM));
\r
119 // AVCodecContext parameters
120 __pCodecCtx->debug_mv = 0; //set by user
121 __pCodecCtx->debug = 0; //set by user
122 __pCodecCtx->workaround_bugs = 1; //set by user
123 __pCodecCtx->lowres = 0; //set by user
124 __pCodecCtx->skip_frame = AVDISCARD_DEFAULT; //set by user
125 __pCodecCtx->skip_idct = AVDISCARD_DEFAULT; //set by user
126 __pCodecCtx->skip_loop_filter = AVDISCARD_DEFAULT; //set by user
127 __pCodecCtx->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK ;
128 __pCodecCtx->idct_algo = FF_IDCT_H264;
129 __pCodecCtx->strict_std_compliance = FF_COMPLIANCE_NORMAL;
131 if (__pCodec->capabilities & CODEC_CAP_TRUNCATED)
133 __pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
136 res = avcodec_open(__pCodecCtx, __pCodec);
137 SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
138 "[%s] AVCODEC Codec Open Failed for CODEC_ID_H264, \
139 result of avcodec_open() = %d ",
140 GetErrorMessage(E_SYSTEM), res);
\r
142 __pParser = av_parser_init(CODEC_ID_H264);
143 SysTryCatch(NID_MEDIA, __pParser != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Construct Failed");
148 if (pMapEnum != null)
152 if (__pCodecCtx != null)
154 avcodec_close(__pCodecCtx);
162 _H264Decoder::Decode(const byte* pSrcBuf, int& srcBufLength,
163 byte*& dstBuf, int& dstBufLength, bool& gotFrame)
165 result r = E_SUCCESS;
167 AVFrame* pVideoFrame = null;
168 AVPacket inputPacket;
170 int remainingBytes = 0;
175 uint8_t* pOutPtr = null;
180 int parsingOffSet = 0;
182 // TODO: add srcBufUsed, dstBufUsed param
184 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");
\r
185 SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && dstBuf != null && srcBufLength > 0 && dstBufLength > 0),
186 E_INVALID_ARG, "Invalid argument is used. The argument is not valid");
187 av_init_packet(&inputPacket);
189 pVideoFrame = avcodec_alloc_frame();
190 SysTryCatch(NID_MEDIA, (pVideoFrame != null), r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
191 "[E_SYSTEM] alloc frame failed");
193 remainingBytes = srcBufLength;
195 while (remainingBytes && __inPacketMode == false)
197 // Parsing the stream to extract the packets
198 dataRead = av_parser_parse2(__pParser, __pCodecCtx, &pOutPtr,
199 &outDataSize, (uint8_t*) (pSrcBuf + parsingOffSet),
200 remainingBytes, pts, dts, pos);
202 // Parsing offset needs to be updated to avoid infinite loop
203 remainingBytes -= dataRead;
204 parsingOffSet += dataRead;
206 if ( outDataSize == 0 || pOutPtr == null)
208 continue; // it should not be in a block .
211 inputPacket.size = outDataSize;
212 inputPacket.data = (uint8_t*) pOutPtr;
214 // Decoding the video packet
215 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
216 SysTryCatch(NID_MEDIA, res >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
217 "[%s] The input data format is not supported \
218 result of avcodec_decode_video2 = %d",
219 GetErrorMessage(E_UNSUPPORTED_FORMAT), res);
\r
221 if (gotPicture) // Parsing of H264 packets done and got picture
224 if (res < srcBufLength)
226 srcBufLength = srcBufLength - remainingBytes ; //Input bytes used
228 goto GOTDECODEDFRAME;
233 // The parser failed to read a frame from bit stream so changing decode mode to packet mode avoiding parsing
234 if ( __inPacketMode == false && (outDataSize == 0 || pOutPtr == null) && remainingBytes == 0)
236 __inPacketMode = true;
241 inputPacket.size = srcBufLength;
242 inputPacket.data = (uint8_t*) pSrcBuf;
244 SysLog(NID_MEDIA, "Before Decode. inputPacket.size :: %d ", srcBufLength);
245 // Decoding the video packet
246 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
247 SysTryCatch(NID_MEDIA, res >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
248 "[%s] The input data format is not supported, \
249 result of avcodec_decode_video2() = %d",
250 GetErrorMessage(E_UNSUPPORTED_FORMAT), res);
\r
254 if (res <= srcBufLength)
256 srcBufLength = res; //Input bytes used
258 goto GOTDECODEDFRAME;
264 SysLog(NID_MEDIA, "Trying Again. Giving Empty Buffer");
265 inputPacket.data = null;
266 inputPacket.size = 0;
267 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
268 SysTryCatch(NID_MEDIA, res >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
269 "[%s] The input data format is not supported \
270 result of avcodec_decode_video2() = %d",
271 GetErrorMessage(E_UNSUPPORTED_FORMAT), res);
\r
278 __decodeCalled = true;
280 if ( __pCodecCtx->pix_fmt == PIX_FMT_YUV420P ) // handling only yuv 420 case
282 SysTryCatch(NID_MEDIA, dstBufLength >= (__pCodecCtx->height*__pCodecCtx->width*3)/2,
283 r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
284 "[%s] Decode Failed Insufficient destination buffer", GetErrorMessage(E_OUT_OF_MEMORY));
\r
285 for (i = 0; i < __pCodecCtx->height; i++)
287 srcOffset = i * pVideoFrame->linesize[0];
288 offset = i * __pCodecCtx->width;
289 memcpy(dstBuf + offset, pVideoFrame->data[0] + srcOffset, __pCodecCtx->width);
291 for (i = 0; i < __pCodecCtx->height / 2; i++)
293 srcOffset = i * pVideoFrame->linesize[1];
294 offset = (__pCodecCtx->height * __pCodecCtx->width) + (i * __pCodecCtx->width) / 2;
295 memcpy(dstBuf + offset, pVideoFrame->data[1] + srcOffset, __pCodecCtx->width / 2);
297 for (i = 0; i < __pCodecCtx->height / 2; i++)
299 srcOffset = i * pVideoFrame->linesize[2];
300 offset = ((__pCodecCtx->height*__pCodecCtx->width*5)/4)+(i*__pCodecCtx->width)/ 2;
301 memcpy(dstBuf + offset, pVideoFrame->data[2] + srcOffset, __pCodecCtx->width / 2);
304 dstBufLength = (__pCodecCtx->height * __pCodecCtx->width * 3) / 2;
314 if (pVideoFrame != null)
316 av_free(pVideoFrame);
321 if (pVideoFrame != null)
323 av_free(pVideoFrame);
329 _H264Decoder::Probe(const byte* pSrcBuf, const int srcBufLength,
330 int& width, int& height, MediaPixelFormat& pixelFormat)
332 result r = E_SUCCESS;
334 AVFrame* pVideoFrame = null;
335 AVPacket inputPacket;
336 uint8_t* pInputData = null;
338 int remainingBytes = 0;
340 uint8_t *pOutPtr = null;
345 int parsingOffSet = 0;
347 // TODO: merge with Decode ?
350 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");
\r
351 SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && srcBufLength > 0), E_INVALID_ARG,
352 "pSrcBuf:0x%x %d", pSrcBuf, srcBufLength);
354 av_init_packet(&inputPacket);
355 inputPacket.size = srcBufLength + FF_INPUT_BUFFER_PADDING_SIZE;
356 pInputData = new (std::nothrow) byte[inputPacket.size + FF_INPUT_BUFFER_PADDING_SIZE];
357 pVideoFrame = avcodec_alloc_frame();
358 SysTryCatch(NID_MEDIA, (pInputData != null && pVideoFrame != null),
359 r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
360 "[E_SYSTEM] Input buffer allocation Failed");
361 memcpy(pInputData, pSrcBuf, srcBufLength);
362 memset(pInputData + srcBufLength, 0, _INPUT_BUFFER_PADDING_SIZE);
363 inputPacket.data = (uint8_t*) pInputData;
365 // Decoding the video packet
366 remainingBytes = inputPacket.size;
370 // Parsing the stream to extract the packets
371 dataRead = av_parser_parse2(__pParser, __pCodecCtx, &pOutPtr, &outDataSize, (uint8_t*) (pSrcBuf + parsingOffSet),
372 remainingBytes, pts, dts, pos);
374 // Parsing offset needs to be updated to avoid infinite loop
375 remainingBytes -= dataRead;
376 parsingOffSet += dataRead;
378 if ( outDataSize == 0 || pOutPtr == null)
380 continue; // no block is required for this if statement.
383 inputPacket.size = outDataSize;
384 inputPacket.data = (uint8_t*) pOutPtr;
386 // Decoding the video packet
387 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
388 SysTryCatch(NID_MEDIA, res >= 0, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
389 "[%s] Invalid argument is used. The argument is not valid, \
390 result of avcodec_decode_video2 = %d",
391 GetErrorMessage(E_INVALID_ARG), res);
\r
396 if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P) // handling only yuv 420 case
398 width = __pCodecCtx->width;
399 height = __pCodecCtx->height;
400 pixelFormat = MEDIA_PIXEL_FORMAT_YUV420P;
405 // All bytes of the frame are not consumed
408 remainingBytes += dataRead - res;
409 parsingOffSet -= dataRead - res;
412 while (remainingBytes);
416 inputPacket.data = null;
417 inputPacket.size = 0;
418 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
420 if (gotPicture && res>= 0)
423 if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P) // handling only yuv 420 case
425 width = __pCodecCtx->width;
426 height = __pCodecCtx->height;
427 pixelFormat = MEDIA_PIXEL_FORMAT_YUV420P;
432 r = E_UNSUPPORTED_FORMAT;
438 av_free(pVideoFrame);
443 if (pInputData != null)
447 if (pVideoFrame != null)
449 av_free(pVideoFrame);
455 _H264Decoder::Reset(void)
457 result r = E_SUCCESS;
459 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
460 avcodec_flush_buffers(__pCodecCtx);
461 __decodeCalled = false;
462 __inPacketMode = false;
467 _H264Decoder::GetValue(MediaPropertyType type, int& value) const
469 result r = E_SUCCESS;
471 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
472 SysTryCatch(NID_MEDIA, __decodeCalled == true, r = E_INVALID_STATE, E_INVALID_STATE,
473 "[%s] The instance is in invalid state", GetErrorMessage(E_INVALID_STATE));
\r
474 SysTryCatch(NID_MEDIA, type>0, r = E_INVALID_ARG, E_INVALID_ARG,
475 "[%s] Invalid argument is used. The argument is not valid", GetErrorMessage(E_INVALID_ARG));
\r
476 SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH && type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
477 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND, "[%s] The instance is not available ", GetErrorMessage(E_OBJ_NOT_FOUND));
\r
481 case MEDIA_PROPERTY_VIDEO_WIDTH:
482 value = __pCodecCtx->width;
485 case MEDIA_PROPERTY_VIDEO_HEIGHT:
486 value = __pCodecCtx->height;
489 case MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT:
490 value = MEDIA_PIXEL_FORMAT_YUV420P;
494 return E_OBJ_NOT_FOUND;
504 _H264Decoder::GetValue(MediaPropertyType type, float& value) const
506 result r = E_SUCCESS;
508 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
509 SysTryCatch(NID_MEDIA, __decodeCalled == true, r = E_INVALID_STATE, E_INVALID_STATE,
510 "[%s] The instance is in invalid state", GetErrorMessage(E_INVALID_STATE));
\r
511 SysTryCatch(NID_MEDIA, type>0, r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] GetValue Failed");
512 SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH && type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
513 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
514 "[%s] The instance is not available ", GetErrorMessage(E_OBJ_NOT_FOUND));
\r
516 return E_OBJ_NOT_FOUND;
522 Tizen::Base::Collection::IListT<MediaPropertyType>*
523 _H264Decoder::GetSupportedPropertyListN(void) const
525 result r = E_SUCCESS;
526 ArrayListT<MediaPropertyType>* pPropList = new (std::nothrow) ArrayListT<MediaPropertyType>;
528 SysTryCatch(NID_MEDIA, pPropList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
529 "[%s] Memory Allocation Failed ", GetErrorMessage(E_OUT_OF_MEMORY));
\r
530 pPropList->Add(MEDIA_PROPERTY_VIDEO_WIDTH);
531 pPropList->Add(MEDIA_PROPERTY_VIDEO_HEIGHT);
532 pPropList->Add(MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT);
541 _H264Decoder::IsPropertySupported(MediaPropertyType type) const
543 result r = E_SUCCESS;
545 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
546 SysTryCatch(NID_MEDIA, (type == MEDIA_PROPERTY_VIDEO_WIDTH || type == MEDIA_PROPERTY_VIDEO_HEIGHT
547 || type == MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT ),
548 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
549 "[%s] The instance is not available ", GetErrorMessage(E_OBJ_NOT_FOUND));
\r