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 <unique_ptr.h>
20 #include <FBaseInteger.h>
21 #include <FBaseColArrayListT.h>
22 #include <FBaseColHashMap.h>
23 #include <FMediaTypes.h>
24 #include <FBaseSysLog.h>
25 #include "FMedia_Ffmpeg.h"
26 #include "FMedia_IVideoEncoder.h"
27 #include "FMedia_Mpeg4Encoder.h"
30 using namespace Tizen::Base;
31 using namespace Tizen::Io;
32 using namespace Tizen::Base::Collection;
34 namespace Tizen { namespace Media
37 static const int _DEFAULT_QSCALE = 3;
40 _Mpeg4Encoder_CreateInstance(void)
42 return new (std::nothrow) _Mpeg4Encoder();
45 _Mpeg4Encoder::_Mpeg4Encoder(void)
53 _Mpeg4Encoder::~_Mpeg4Encoder(void)
55 if (__pCodecCtx != null)
57 avcodec_close(__pCodecCtx);
69 _Mpeg4Encoder::Construct(const Tizen::Base::Collection::HashMap* pOption)
74 Integer* pValue = null;
78 SysTryReturnResult(NID_MEDIA, __pCodecCtx == null, E_INVALID_STATE, "already constructed");
80 av_log_set_level (AV_LOG_QUIET);
81 avcodec_register_all();
83 __pCodec = avcodec_find_encoder(AV_CODEC_ID_MPEG4);
84 SysTryCatch(NID_MEDIA, __pCodec != null, r = E_SYSTEM, E_SYSTEM, "[%s] Failed to get avcodec encoder",GetErrorMessage(E_SYSTEM));
86 __pCodecCtx = avcodec_alloc_context3(__pCodec);
87 SysTryCatch(NID_MEDIA, __pCodecCtx != null, r = E_SYSTEM, E_SYSTEM,
88 "[%s] Failed to allocate avcodec context", GetErrorMessage(E_SYSTEM));
90 __pCodecCtx->bit_rate = BITRATE_IN_BITS;
91 __pCodecCtx->width = WIDTH;
92 __pCodecCtx->height = HEIGHT;
93 __pCodecCtx->time_base.den = 15;
94 __pCodecCtx->time_base.num = 1;
95 __pCodecCtx->gop_size = GOP;
96 __pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
97 __pCodecCtx->max_b_frames = 0;
98 __pCodecCtx->qmin = MIN_QP;
99 __pCodecCtx->qmax = MAX_QP;
100 __pCodecCtx->mpeg_quant = 1;
102 // The initialization values are given in the Hashmap
105 std::unique_ptr<IMapEnumerator> pMapEnum(pOption->GetMapEnumeratorN());
106 SysTryCatch(NID_MEDIA, pMapEnum.get() != null, r = E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Propagating");
108 while (pMapEnum.get()->MoveNext() == E_SUCCESS)
110 pKey = dynamic_cast<Integer*> (pMapEnum.get()->GetKey());
111 pValue = dynamic_cast<Integer*> (pMapEnum.get()->GetValue());
113 if (pKey == null || pValue == null)
119 value = pValue->ToInt();
123 case MEDIA_PROPERTY_VIDEO_WIDTH:
124 SysTryCatch(NID_MEDIA, value > 0 && value < MAX_WIDTH,
125 r = E_INVALID_ARG, E_INVALID_ARG, "[%s] Invalid argument is used: width %d", GetErrorMessage(E_INVALID_ARG), value);
126 __pCodecCtx->width = value;
129 case MEDIA_PROPERTY_VIDEO_HEIGHT:
130 SysTryCatch(NID_MEDIA, value > 0 && value < MAX_HEIGHT,
131 r = E_INVALID_ARG, E_INVALID_ARG, "[%s] Invalid argument is used: height %d", GetErrorMessage(E_INVALID_ARG), value);
132 __pCodecCtx->height = value;
135 case MEDIA_PROPERTY_VIDEO_FRAME_RATE:
136 SysTryCatch(NID_MEDIA, value > 0, r = E_INVALID_ARG, E_INVALID_ARG,
137 "[%s] Invalid argument is used: framerate %d", GetErrorMessage(E_INVALID_ARG), value);
138 __pCodecCtx->time_base.den = value;
139 __pCodecCtx->time_base.num = 1;
142 case MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT:
143 SysTryCatch(NID_MEDIA, value == MEDIA_PIXEL_FORMAT_YUV420P, r = E_INVALID_ARG, E_INVALID_ARG,
144 "[%s] Invalid argument is used: pixelFormat %d", GetErrorMessage(E_INVALID_ARG), value);
145 __pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
148 case MEDIA_PROPERTY_VIDEO_BIT_RATE:
149 SysTryCatch(NID_MEDIA, value >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
150 "[%s] Invalid argument is used: bitRate %d", GetErrorMessage(E_INVALID_ARG), value);
151 __pCodecCtx->bit_rate = value;
154 case MEDIA_PROPERTY_VIDEO_QUANTIZATION_PARAMETER :
155 SysTryCatch(NID_MEDIA, value >= MIN_QP && value <= MAX_QP,
156 r = E_INVALID_ARG, E_INVALID_ARG,
157 "[%s] Invalid argument is used: quantization parameter %d", GetErrorMessage(E_INVALID_ARG), value);
158 //__pCodecCtx->mpeg_quant = value;
161 case MEDIA_PROPERTY_VIDEO_QUANTIZATION_MIN :
162 SysTryCatch(NID_MEDIA, value >= MIN_QP && value <= MAX_QP,
163 r = E_INVALID_ARG, E_INVALID_ARG,
164 "[%s] Invalid argument is used: quantization min %d", GetErrorMessage(E_INVALID_ARG), value);
165 __pCodecCtx->qmin = value;
168 case MEDIA_PROPERTY_VIDEO_QUANTIZATION_MAX :
169 SysTryCatch(NID_MEDIA, value >= MIN_QP && value <= MAX_QP,
170 r = E_INVALID_ARG, E_INVALID_ARG,
171 "[%s] Invalid argument is used: quantization max %d", GetErrorMessage(E_INVALID_ARG), value);
172 __pCodecCtx->qmax = value;
175 case MEDIA_PROPERTY_VIDEO_GOP_SIZE :
176 SysTryCatch(NID_MEDIA, value >= 0,
177 r = E_INVALID_ARG, E_INVALID_ARG, "[%s] Invalid argument is used: gop size %d", GetErrorMessage(E_INVALID_ARG), value);
178 __pCodecCtx->gop_size = value;
181 case MEDIA_PROPERTY_VIDEO_PACKET_SIZE :
182 SysTryCatch(NID_MEDIA, value >= 0,
183 r = E_INVALID_ARG, E_INVALID_ARG, "[%s] Invalid argument is used: slice size %d", GetErrorMessage(E_INVALID_ARG), value);
184 __pCodecCtx->rtp_payload_size = value;
187 case MEDIA_PROPERTY_VIDEO_USE_AC_PREDICTION :
188 SysTryCatch(NID_MEDIA, value == 0 || value == 1, r = E_INVALID_ARG, E_INVALID_ARG,
189 "[%s] Invalid argument is used: slice size %d", GetErrorMessage(E_INVALID_ARG), value);
192 case MEDIA_PROPERTY_VIDEO_USE_HEADER_EXTENSION_CODE :
193 SysTryCatch(NID_MEDIA, value == 0 || value == 1, r = E_INVALID_ARG, E_INVALID_ARG,
194 "[%s] Invalid argument is used: slice size %d", GetErrorMessage(E_INVALID_ARG), value);
197 case MEDIA_PROPERTY_VIDEO_USE_FRAME_SKIP:
198 SysTryCatch(NID_MEDIA, value == 0 || value == 1, r = E_INVALID_ARG, E_INVALID_ARG,
199 "[%s] Invalid argument is used: slice size %d", GetErrorMessage(E_INVALID_ARG), value);
209 res = avcodec_open2(__pCodecCtx, __pCodec, NULL);
211 SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM,
212 "[%s] avcodec open failed %d ", GetErrorMessage(E_SYSTEM), res);
214 __pFrame = avcodec_alloc_frame();
215 SysTryCatch(NID_MEDIA, __pFrame != null, r = E_SYSTEM, E_SYSTEM, "[%s] avcodec alloc frame failed", GetErrorMessage(E_SYSTEM));
217 __pFrame->format = __pCodecCtx->pix_fmt;
219 for (int i = 0; i < 4; i++)
221 __pFrame->data[i] = null;
222 __pFrame->linesize[i] = 0;
232 avcodec_close(__pCodecCtx);
233 av_free(__pCodecCtx);
241 _Mpeg4Encoder::Encode(const byte* srcBuf, int& srcBufLength, byte*& dstBuf, int& dstBufLength)
243 result r = E_SUCCESS;
246 int minSrcBufLength = 0;
248 unique_ptr<AVPacket, _FfmpegDeleter> pPkt(null, ffmpegDeleter);
250 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
252 minSrcBufLength = __pCodecCtx->width * __pCodecCtx->height * 3 / 2;
253 SysTryCatch(NID_MEDIA, (srcBuf != null && dstBuf != null && srcBufLength >= minSrcBufLength && dstBufLength >= FF_MIN_BUFFER_SIZE),
254 r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
255 "[E_INVALID_ARG] Encode Failed : 0x%x %d %d 0x%x %d %d",
256 srcBuf, srcBufLength, minSrcBufLength, dstBuf, dstBufLength, FF_MIN_BUFFER_SIZE);
258 __pFrame->data[0] = (uint8_t*)srcBuf;
259 __pFrame->data[1] = (uint8_t*)srcBuf + __pCodecCtx->width * __pCodecCtx->height;
260 __pFrame->data[2] = (uint8_t*)srcBuf + __pCodecCtx->width * __pCodecCtx->height * 5 / 4;
261 __pFrame->linesize[0] = __pCodecCtx->width;
262 __pFrame->linesize[1] = __pCodecCtx->width / 2;
263 __pFrame->linesize[2] = __pCodecCtx->width / 2;
265 if (__firstFrame && __pCodecCtx->extradata)
267 SysLog(NID_MEDIA, "extradata:%x %d", __pCodecCtx->extradata, __pCodecCtx->extradata_size);
268 memcpy(dstBuf, __pCodecCtx->extradata, __pCodecCtx->extradata_size);
269 __firstFrame = false;
270 dstBufLength -= __pCodecCtx->extradata_size;
271 outIndex += __pCodecCtx->extradata_size;
274 pPkt.reset(new (std::nothrow) AVPacket);
275 SysTryReturnResult(NID_MEDIA, pPkt.get() != null, E_OUT_OF_MEMORY, "new AVPacket failed.");
276 av_init_packet(pPkt.get());
277 pPkt->data = NULL; // packet data will be allocated by the encoder
281 res = avcodec_encode_video2(__pCodecCtx, pPkt.get(), __pFrame, &gotOutput);
282 SysTryCatch(NID_MEDIA, res >= 0, r = E_SYSTEM, E_SYSTEM, "[%s] Video Encode Failed %d", GetErrorMessage(E_SYSTEM), res);
286 SysTryCatch(NID_MEDIA, pPkt->size <= dstBufLength, r = E_INVALID_ARG, E_INVALID_ARG,
287 "[%s] dst buffer is insufficient:%d %d", GetErrorMessage(E_INVALID_ARG), dstBufLength, pPkt->size);
288 memcpy(dstBuf+outIndex, pPkt->data, pPkt->size);
289 srcBufLength = minSrcBufLength;
290 dstBufLength = pPkt->size + outIndex;
294 srcBufLength = minSrcBufLength;
295 dstBufLength = outIndex;
304 _Mpeg4Encoder::Reset(void)
306 result r = E_SUCCESS;
308 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
309 avcodec_flush_buffers(__pCodecCtx);
314 _Mpeg4Encoder::SetValue(MediaPropertyType type, int value)
316 result r = E_SUCCESS;
318 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
319 SysTryCatch(NID_MEDIA, value >= 0, r = E_INVALID_ARG, E_INVALID_ARG,
320 "[%s] Invalid argument is used. type:%d", GetErrorMessage(E_SYSTEM), type);
321 SysTryCatch(NID_MEDIA, type > 0, r = E_INVALID_ARG, E_INVALID_ARG,
322 "[%s] Invalid argument is used. type:%d", GetErrorMessage(E_SYSTEM), type);
323 SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH && type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
324 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND, "[%s] object not found: type:%d", GetErrorMessage(E_OBJ_NOT_FOUND),type);
328 case MEDIA_PROPERTY_VIDEO_WIDTH:
329 SysTryCatch(NID_MEDIA, value < MAX_WIDTH, r = E_INVALID_ARG, E_INVALID_ARG,
330 "[%s] Invalid argument is used. type:%d", GetErrorMessage(E_INVALID_ARG), type);
331 __pCodecCtx->width = value;
334 case MEDIA_PROPERTY_VIDEO_HEIGHT:
335 SysTryCatch(NID_MEDIA, value < MAX_HEIGHT, r = E_INVALID_ARG, E_INVALID_ARG,
336 "[%s] Invalid argument is used. type:%d", GetErrorMessage(E_INVALID_ARG), type);
337 __pCodecCtx->height = value;
340 case MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT:
341 __pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
344 case MEDIA_PROPERTY_VIDEO_FRAME_RATE:
345 __pCodecCtx->time_base.den = 15;
346 __pCodecCtx->time_base.num = 1;
349 case MEDIA_PROPERTY_VIDEO_BIT_RATE:
350 __pCodecCtx->bit_rate = value;
354 case MEDIA_PROPERTY_VIDEO_QUANTIZATION_PARAMETER :
355 __pCodecCtx->mpeg_quant = value;
358 case MEDIA_PROPERTY_VIDEO_QUANTIZATION_MIN :
359 __pCodecCtx->qmin = value;
362 case MEDIA_PROPERTY_VIDEO_QUANTIZATION_MAX :
363 __pCodecCtx->qmax = value;
366 case MEDIA_PROPERTY_VIDEO_GOP_SIZE :
367 __pCodecCtx->gop_size = value;
370 case MEDIA_PROPERTY_VIDEO_PACKET_SIZE :
371 __pCodecCtx->rtp_payload_size = value;
375 return E_OBJ_NOT_FOUND;
385 _Mpeg4Encoder::SetValue(MediaPropertyType type, bool value)
387 result r = E_SUCCESS;
389 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
390 SysTryCatch(NID_MEDIA, type > 0, r = E_INVALID_ARG, E_INVALID_ARG, "[%s] Invalid argument is used", GetErrorMessage(E_INVALID_ARG));
391 SysTryCatch(NID_MEDIA,(value ==0 || value == 1), r = E_INVALID_ARG, E_INVALID_ARG, "[%s] Invalid argument is used", GetErrorMessage(E_INVALID_ARG));
392 SysTryCatch(NID_MEDIA, type >= MEDIA_PROPERTY_VIDEO_WIDTH || type <= MEDIA_PROPERTY_AUDIO_SAMPLE_RATE,
393 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND, "[E_OBJ_NOT_FOUND] Object Not Found",GetErrorMessage(E_OBJ_NOT_FOUND));
396 case MEDIA_PROPERTY_VIDEO_FORCE_SKIP_FRAME:
397 __pCodecCtx->skip_frame = AVDISCARD_DEFAULT;
400 case MEDIA_PROPERTY_VIDEO_FORCE_INTRA_CODING:
401 __pCodecCtx->skip_idct = AVDISCARD_DEFAULT;
405 return E_OBJ_NOT_FOUND;
416 Tizen::Base::Collection::IListT<MediaPropertyType>*
417 _Mpeg4Encoder::GetSupportedPropertyListN(void) const
419 result r = E_SUCCESS;
420 ArrayListT<MediaPropertyType>* pPropList = new (std::nothrow) ArrayListT<MediaPropertyType>;
422 SysTryCatch(NID_MEDIA, pPropList != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY,
423 "[%s] Memory allocation Failed",GetErrorMessage(E_OUT_OF_MEMORY));
424 pPropList->Add(MEDIA_PROPERTY_VIDEO_WIDTH);
425 pPropList->Add(MEDIA_PROPERTY_VIDEO_HEIGHT);
426 pPropList->Add(MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT);
427 pPropList->Add(MEDIA_PROPERTY_VIDEO_FRAME_RATE);
428 pPropList->Add(MEDIA_PROPERTY_VIDEO_BIT_RATE);
429 pPropList->Add(MEDIA_PROPERTY_VIDEO_QUANTIZATION_PARAMETER);
430 pPropList->Add( MEDIA_PROPERTY_VIDEO_QUANTIZATION_MAX);
431 pPropList->Add(MEDIA_PROPERTY_VIDEO_QUANTIZATION_MIN);
432 pPropList->Add(MEDIA_PROPERTY_VIDEO_GOP_SIZE);
433 pPropList->Add(MEDIA_PROPERTY_VIDEO_PACKET_SIZE);
434 pPropList->Add(MEDIA_PROPERTY_VIDEO_USE_FRAME_SKIP);
435 pPropList->Add(MEDIA_PROPERTY_VIDEO_USE_AC_PREDICTION);
436 pPropList->Add(MEDIA_PROPERTY_VIDEO_USE_HEADER_EXTENSION_CODE);
437 pPropList->Add(MEDIA_PROPERTY_VIDEO_FORCE_SKIP_FRAME);
438 pPropList->Add(MEDIA_PROPERTY_VIDEO_FORCE_INTRA_CODING);
448 _Mpeg4Encoder::IsPropertySupported(MediaPropertyType type) const
450 result r = E_SUCCESS;
452 SysTryReturnResult(NID_MEDIA, __pCodecCtx, E_INVALID_STATE, "not constructed");
453 SysTryCatch(NID_MEDIA, ( type == MEDIA_PROPERTY_VIDEO_WIDTH || type == MEDIA_PROPERTY_VIDEO_HEIGHT
454 || type == MEDIA_PROPERTY_VIDEO_PIXEL_FORMAT || type == MEDIA_PROPERTY_VIDEO_FRAME_RATE
455 || type == MEDIA_PROPERTY_VIDEO_BIT_RATE || type == MEDIA_PROPERTY_VIDEO_QUANTIZATION_PARAMETER || type ==
456 MEDIA_PROPERTY_VIDEO_QUANTIZATION_MIN || type == MEDIA_PROPERTY_VIDEO_QUANTIZATION_MAX || type == MEDIA_PROPERTY_VIDEO_GOP_SIZE || type ==
457 MEDIA_PROPERTY_VIDEO_PACKET_SIZE || type == MEDIA_PROPERTY_VIDEO_USE_FRAME_SKIP || type == MEDIA_PROPERTY_VIDEO_USE_AC_PREDICTION || type ==
458 MEDIA_PROPERTY_VIDEO_USE_HEADER_EXTENSION_CODE || type == MEDIA_PROPERTY_VIDEO_FORCE_SKIP_FRAME || type == MEDIA_PROPERTY_VIDEO_FORCE_INTRA_CODING),
459 r = E_OBJ_NOT_FOUND, E_OBJ_NOT_FOUND,
460 "[E_OBJ_NOT_FOUND] Object not found. type:%d", type);