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 __pCodec = avcodec_find_decoder(CODEC_ID_H264);
115 SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM, "[%s] AVCODEC Find Decoder Failed for CODEC_ID_H264", GetErrorMessage(E_SYSTEM));
117 __pCodecCtx = avcodec_alloc_context3(__pCodec);
118 SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM, "[%s] AVCODEC Context Allcoation Failed", GetErrorMessage(E_SYSTEM));
\r
120 // AVCodecContext parameters
121 __pCodecCtx->debug_mv = 0; //set by user
122 __pCodecCtx->debug = 0; //set by user
123 __pCodecCtx->workaround_bugs = 1; //set by user
124 __pCodecCtx->lowres = 0; //set by user
125 __pCodecCtx->skip_frame = AVDISCARD_DEFAULT; //set by user
126 __pCodecCtx->skip_idct = AVDISCARD_DEFAULT; //set by user
127 __pCodecCtx->skip_loop_filter = AVDISCARD_DEFAULT; //set by user
128 __pCodecCtx->error_concealment = FF_EC_GUESS_MVS | FF_EC_DEBLOCK ;
129 __pCodecCtx->idct_algo = FF_IDCT_H264;
130 __pCodecCtx->strict_std_compliance = FF_COMPLIANCE_NORMAL;
132 if (__pCodec->capabilities & CODEC_CAP_TRUNCATED)
134 __pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
137 res = avcodec_open2(__pCodecCtx, __pCodec, null);
138 SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
139 "[%s] AVCODEC Codec Open Failed for CODEC_ID_H264, \
140 result of avcodec_open() = %d ",
141 GetErrorMessage(E_SYSTEM), res);
\r
143 __pParser = av_parser_init(CODEC_ID_H264);
144 SysTryCatch(NID_MEDIA, __pParser != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Construct Failed");
149 if (pMapEnum != null)
153 if (__pCodecCtx != null)
155 avcodec_close(__pCodecCtx);
163 _H264Decoder::Decode(const byte* pSrcBuf, int& srcBufLength,
164 byte*& dstBuf, int& dstBufLength, bool& gotFrame)
166 result r = E_SUCCESS;
168 AVFrame* pVideoFrame = null;
169 AVPacket inputPacket;
171 int remainingBytes = 0;
176 uint8_t* pOutPtr = null;
181 int parsingOffSet = 0;
183 // TODO: add srcBufUsed, dstBufUsed param
185 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");
\r
186 SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && dstBuf != null && srcBufLength > 0 && dstBufLength > 0),
187 E_INVALID_ARG, "Invalid argument is used. The argument is not valid");
188 av_init_packet(&inputPacket);
190 pVideoFrame = avcodec_alloc_frame();
191 SysTryCatch(NID_MEDIA, (pVideoFrame != null), r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
192 "[E_SYSTEM] alloc frame failed");
194 remainingBytes = srcBufLength;
196 while (remainingBytes && __inPacketMode == false)
198 // Parsing the stream to extract the packets
199 dataRead = av_parser_parse2(__pParser, __pCodecCtx, &pOutPtr,
200 &outDataSize, (uint8_t*) (pSrcBuf + parsingOffSet),
201 remainingBytes, pts, dts, pos);
203 // Parsing offset needs to be updated to avoid infinite loop
204 remainingBytes -= dataRead;
205 parsingOffSet += dataRead;
207 if ( outDataSize == 0 || pOutPtr == null)
209 continue; // it should not be in a block .
212 inputPacket.size = outDataSize;
213 inputPacket.data = (uint8_t*) pOutPtr;
215 // Decoding the video packet
216 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
217 SysTryCatch(NID_MEDIA, res >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
218 "[%s] The input data format is not supported \
219 result of avcodec_decode_video2 = %d",
220 GetErrorMessage(E_UNSUPPORTED_FORMAT), res);
\r
222 if (gotPicture) // Parsing of H264 packets done and got picture
225 if (res < srcBufLength)
227 srcBufLength = srcBufLength - remainingBytes ; //Input bytes used
229 goto GOTDECODEDFRAME;
234 // The parser failed to read a frame from bit stream so changing decode mode to packet mode avoiding parsing
235 if ( __inPacketMode == false && (outDataSize == 0 || pOutPtr == null) && remainingBytes == 0)
237 __inPacketMode = true;
242 inputPacket.size = srcBufLength;
243 inputPacket.data = (uint8_t*) pSrcBuf;
245 SysLog(NID_MEDIA, "Before Decode. inputPacket.size :: %d ", srcBufLength);
246 // Decoding the video packet
247 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
248 SysTryCatch(NID_MEDIA, res >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
249 "[%s] The input data format is not supported, \
250 result of avcodec_decode_video2() = %d",
251 GetErrorMessage(E_UNSUPPORTED_FORMAT), res);
\r
255 if (res <= srcBufLength)
257 srcBufLength = res; //Input bytes used
259 goto GOTDECODEDFRAME;
265 SysLog(NID_MEDIA, "Trying Again. Giving Empty Buffer");
266 inputPacket.data = null;
267 inputPacket.size = 0;
268 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
269 SysTryCatch(NID_MEDIA, res >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
270 "[%s] The input data format is not supported \
271 result of avcodec_decode_video2() = %d",
272 GetErrorMessage(E_UNSUPPORTED_FORMAT), res);
\r
279 __decodeCalled = true;
281 if ( __pCodecCtx->pix_fmt == PIX_FMT_YUV420P ) // handling only yuv 420 case
283 SysTryCatch(NID_MEDIA, dstBufLength >= (__pCodecCtx->height*__pCodecCtx->width*3)/2,
284 r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
285 "[%s] Decode Failed Insufficient destination buffer", GetErrorMessage(E_OUT_OF_MEMORY));
\r
286 for (i = 0; i < __pCodecCtx->height; i++)
288 srcOffset = i * pVideoFrame->linesize[0];
289 offset = i * __pCodecCtx->width;
290 memcpy(dstBuf + offset, pVideoFrame->data[0] + srcOffset, __pCodecCtx->width);
292 for (i = 0; i < __pCodecCtx->height / 2; i++)
294 srcOffset = i * pVideoFrame->linesize[1];
295 offset = (__pCodecCtx->height * __pCodecCtx->width) + (i * __pCodecCtx->width) / 2;
296 memcpy(dstBuf + offset, pVideoFrame->data[1] + srcOffset, __pCodecCtx->width / 2);
298 for (i = 0; i < __pCodecCtx->height / 2; i++)
300 srcOffset = i * pVideoFrame->linesize[2];
301 offset = ((__pCodecCtx->height*__pCodecCtx->width*5)/4)+(i*__pCodecCtx->width)/ 2;
302 memcpy(dstBuf + offset, pVideoFrame->data[2] + srcOffset, __pCodecCtx->width / 2);
305 dstBufLength = (__pCodecCtx->height * __pCodecCtx->width * 3) / 2;
315 if (pVideoFrame != null)
317 av_free(pVideoFrame);
322 if (pVideoFrame != null)
324 av_free(pVideoFrame);
330 _H264Decoder::Probe(const byte* pSrcBuf, const int srcBufLength,
331 int& width, int& height, MediaPixelFormat& pixelFormat)
333 result r = E_SUCCESS;
335 AVFrame* pVideoFrame = null;
336 AVPacket inputPacket;
337 uint8_t* pInputData = null;
339 int remainingBytes = 0;
341 uint8_t *pOutPtr = null;
346 int parsingOffSet = 0;
348 // TODO: merge with Decode ?
351 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "The instance is in invalid state");
\r
352 SysTryReturnResult(NID_MEDIA, (pSrcBuf != null && srcBufLength > 0), E_INVALID_ARG,
353 "pSrcBuf:0x%x %d", pSrcBuf, srcBufLength);
355 av_init_packet(&inputPacket);
356 inputPacket.size = srcBufLength + FF_INPUT_BUFFER_PADDING_SIZE;
357 pInputData = new (std::nothrow) byte[inputPacket.size + FF_INPUT_BUFFER_PADDING_SIZE];
358 pVideoFrame = avcodec_alloc_frame();
359 SysTryCatch(NID_MEDIA, (pInputData != null && pVideoFrame != null),
360 r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
361 "[E_SYSTEM] Input buffer allocation Failed");
362 memcpy(pInputData, pSrcBuf, srcBufLength);
363 memset(pInputData + srcBufLength, 0, _INPUT_BUFFER_PADDING_SIZE);
364 inputPacket.data = (uint8_t*) pInputData;
366 // Decoding the video packet
367 remainingBytes = inputPacket.size;
371 // Parsing the stream to extract the packets
372 dataRead = av_parser_parse2(__pParser, __pCodecCtx, &pOutPtr, &outDataSize, (uint8_t*) (pSrcBuf + parsingOffSet),
373 remainingBytes, pts, dts, pos);
375 // Parsing offset needs to be updated to avoid infinite loop
376 remainingBytes -= dataRead;
377 parsingOffSet += dataRead;
379 if ( outDataSize == 0 || pOutPtr == null)
381 continue; // no block is required for this if statement.
384 inputPacket.size = outDataSize;
385 inputPacket.data = (uint8_t*) pOutPtr;
387 // Decoding the video packet
388 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
389 SysTryCatch(NID_MEDIA, res >= 0, r = E_UNSUPPORTED_FORMAT, E_UNSUPPORTED_FORMAT,
390 "[%s] Invalid argument is used. The argument is not valid, \
391 result of avcodec_decode_video2 = %d",
392 GetErrorMessage(E_INVALID_ARG), res);
\r
397 if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P) // handling only yuv 420 case
399 width = __pCodecCtx->width;
400 height = __pCodecCtx->height;
401 pixelFormat = MEDIA_PIXEL_FORMAT_YUV420P;
406 // All bytes of the frame are not consumed
409 remainingBytes += dataRead - res;
410 parsingOffSet -= dataRead - res;
413 while (remainingBytes);
417 inputPacket.data = null;
418 inputPacket.size = 0;
419 res = avcodec_decode_video2(__pCodecCtx, pVideoFrame, &gotPicture, &inputPacket);
421 if (gotPicture && res>= 0)
424 if (__pCodecCtx->pix_fmt == PIX_FMT_YUV420P) // handling only yuv 420 case
426 width = __pCodecCtx->width;
427 height = __pCodecCtx->height;
428 pixelFormat = MEDIA_PIXEL_FORMAT_YUV420P;
433 r = E_UNSUPPORTED_FORMAT;
439 av_free(pVideoFrame);
444 if (pInputData != null)
448 if (pVideoFrame != null)
450 av_free(pVideoFrame);
456 _H264Decoder::Reset(void)
458 result r = E_SUCCESS;
460 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
461 avcodec_flush_buffers(__pCodecCtx);
462 __decodeCalled = false;
463 __inPacketMode = false;
468 _H264Decoder::GetValue(MediaPropertyType type, int& value) const
470 result r = E_SUCCESS;
472 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
473 SysTryCatch(NID_MEDIA, __decodeCalled == true, r = E_INVALID_STATE, E_INVALID_STATE,
474 "[%s] The instance is in invalid state", GetErrorMessage(E_INVALID_STATE));
\r
475 SysTryCatch(NID_MEDIA, type>0, r = E_INVALID_ARG, E_INVALID_ARG,
476 "[%s] Invalid argument is used. The argument is not valid", GetErrorMessage(E_INVALID_ARG));
\r
477 SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH && type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
478 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND, "[%s] The instance is not available ", GetErrorMessage(E_OBJ_NOT_FOUND));
\r
482 case MEDIA_PROPERTY_VIDEO_WIDTH:
483 value = __pCodecCtx->width;
486 case MEDIA_PROPERTY_VIDEO_HEIGHT:
487 value = __pCodecCtx->height;
490 case MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT:
491 value = MEDIA_PIXEL_FORMAT_YUV420P;
495 return E_OBJ_NOT_FOUND;
505 _H264Decoder::GetValue(MediaPropertyType type, float& value) const
507 result r = E_SUCCESS;
509 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
510 SysTryCatch(NID_MEDIA, __decodeCalled == true, r = E_INVALID_STATE, E_INVALID_STATE,
511 "[%s] The instance is in invalid state", GetErrorMessage(E_INVALID_STATE));
\r
512 SysTryCatch(NID_MEDIA, type>0, r = E_INVALID_ARG, E_INVALID_ARG, "[E_INVALID_ARG] GetValue Failed");
513 SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH && type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
514 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
515 "[%s] The instance is not available ", GetErrorMessage(E_OBJ_NOT_FOUND));
\r
517 return E_OBJ_NOT_FOUND;
523 Tizen::Base::Collection::IListT<MediaPropertyType>*
524 _H264Decoder::GetSupportedPropertyListN(void) const
526 result r = E_SUCCESS;
527 ArrayListT<MediaPropertyType>* pPropList = new (std::nothrow) ArrayListT<MediaPropertyType>;
529 SysTryCatch(NID_MEDIA, pPropList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
530 "[%s] Memory Allocation Failed ", GetErrorMessage(E_OUT_OF_MEMORY));
\r
531 pPropList->Add(MEDIA_PROPERTY_VIDEO_WIDTH);
532 pPropList->Add(MEDIA_PROPERTY_VIDEO_HEIGHT);
533 pPropList->Add(MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT);
542 _H264Decoder::IsPropertySupported(MediaPropertyType type) const
544 result r = E_SUCCESS;
546 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "Not constructed");
547 SysTryCatch(NID_MEDIA, (type == MEDIA_PROPERTY_VIDEO_WIDTH || type == MEDIA_PROPERTY_VIDEO_HEIGHT
548 || type == MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT ),
549 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
550 "[%s] The instance is not available ", GetErrorMessage(E_OBJ_NOT_FOUND));
\r