blob: e8e4569955a8fadf65d924c17a5eaddf7b699e40 [file] [log] [blame]
Benny Prijonoc45d9512010-12-10 11:04:30 +00001/* $Id$ */
2/*
3 * Copyright (C) 2010 Teluu Inc. (http://www.teluu.com)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjmedia-codec/ffmpeg_codecs.h>
20#include <pjmedia-codec/h263_packetizer.h>
21#include <pjmedia/errno.h>
22#include <pj/assert.h>
23#include <pj/list.h>
24#include <pj/log.h>
25#include <pj/math.h>
26#include <pj/pool.h>
27#include <pj/string.h>
28#include <pj/os.h>
29
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +000030
Benny Prijonoc45d9512010-12-10 11:04:30 +000031/*
32 * Only build this file if PJMEDIA_HAS_FFMPEG_CODEC != 0
33 */
34#if defined(PJMEDIA_HAS_FFMPEG_CODEC) && PJMEDIA_HAS_FFMPEG_CODEC != 0
35
36#define THIS_FILE "ffmpeg_codecs.c"
37
38#include "../pjmedia/ffmpeg_util.h"
39#include <libavcodec/avcodec.h>
40#include <libavformat/avformat.h>
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +000041#include <libswscale/swscale.h>
Benny Prijonoc45d9512010-12-10 11:04:30 +000042
43
44#define PJMEDIA_FORMAT_FFMPEG_UNKNOWN PJMEDIA_FORMAT_PACK('f','f','0','0');
45
46
47/* Prototypes for FFMPEG codecs factory */
48static pj_status_t ffmpeg_test_alloc( pjmedia_vid_codec_factory *factory,
49 const pjmedia_vid_codec_info *id );
50static pj_status_t ffmpeg_default_attr( pjmedia_vid_codec_factory *factory,
51 const pjmedia_vid_codec_info *info,
52 pjmedia_vid_codec_param *attr );
53static pj_status_t ffmpeg_enum_codecs( pjmedia_vid_codec_factory *factory,
54 unsigned *count,
55 pjmedia_vid_codec_info codecs[]);
56static pj_status_t ffmpeg_alloc_codec( pjmedia_vid_codec_factory *factory,
57 const pjmedia_vid_codec_info *info,
58 pjmedia_vid_codec **p_codec);
59static pj_status_t ffmpeg_dealloc_codec( pjmedia_vid_codec_factory *factory,
60 pjmedia_vid_codec *codec );
61
62/* Prototypes for FFMPEG codecs implementation. */
63static pj_status_t ffmpeg_codec_init( pjmedia_vid_codec *codec,
64 pj_pool_t *pool );
65static pj_status_t ffmpeg_codec_open( pjmedia_vid_codec *codec,
66 pjmedia_vid_codec_param *attr );
67static pj_status_t ffmpeg_codec_close( pjmedia_vid_codec *codec );
68static pj_status_t ffmpeg_codec_modify(pjmedia_vid_codec *codec,
69 const pjmedia_vid_codec_param *attr );
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +000070static pj_status_t ffmpeg_codec_get_param(pjmedia_vid_codec *codec,
71 pjmedia_vid_codec_param *param);
Benny Prijonoc45d9512010-12-10 11:04:30 +000072static pj_status_t ffmpeg_packetize ( pjmedia_vid_codec *codec,
73 pj_uint8_t *buf,
74 pj_size_t buf_len,
75 unsigned *pos,
76 const pj_uint8_t **payload,
77 pj_size_t *payload_len);
78static pj_status_t ffmpeg_unpacketize(pjmedia_vid_codec *codec,
79 const pj_uint8_t *payload,
80 pj_size_t payload_len,
81 pj_uint8_t *buf,
82 pj_size_t *buf_len);
83static pj_status_t ffmpeg_codec_encode( pjmedia_vid_codec *codec,
84 const pjmedia_frame *input,
85 unsigned output_buf_len,
86 pjmedia_frame *output);
87static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec,
88 const pjmedia_frame *input,
89 unsigned output_buf_len,
90 pjmedia_frame *output);
91static pj_status_t ffmpeg_codec_recover( pjmedia_vid_codec *codec,
92 unsigned output_buf_len,
93 pjmedia_frame *output);
94
95/* Definition for FFMPEG codecs operations. */
96static pjmedia_vid_codec_op ffmpeg_op =
97{
98 &ffmpeg_codec_init,
99 &ffmpeg_codec_open,
100 &ffmpeg_codec_close,
101 &ffmpeg_codec_modify,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000102 &ffmpeg_codec_get_param,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000103 &ffmpeg_packetize,
104 &ffmpeg_unpacketize,
105 &ffmpeg_codec_encode,
106 &ffmpeg_codec_decode,
107 NULL //&ffmpeg_codec_recover
108};
109
110/* Definition for FFMPEG codecs factory operations. */
111static pjmedia_vid_codec_factory_op ffmpeg_factory_op =
112{
113 &ffmpeg_test_alloc,
114 &ffmpeg_default_attr,
115 &ffmpeg_enum_codecs,
116 &ffmpeg_alloc_codec,
117 &ffmpeg_dealloc_codec
118};
119
120
Benny Prijonoc45d9512010-12-10 11:04:30 +0000121/* FFMPEG codecs factory */
122static struct ffmpeg_factory {
123 pjmedia_vid_codec_factory base;
124 pjmedia_vid_codec_mgr *mgr;
125 pj_pool_factory *pf;
126 pj_pool_t *pool;
127 pj_mutex_t *mutex;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000128} ffmpeg_factory;
129
130
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000131typedef struct ffmpeg_codec_desc ffmpeg_codec_desc;
132
133/* ITU resolution ID */
134typedef enum itu_res_id {
135 ITU_RES_SQCIF,
136 ITU_RES_QCIF,
137 ITU_RES_CIF,
138 ITU_RES_4CIF,
139 ITU_RES_16CIF,
140 ITU_RES_CUSTOM,
141} itu_res_id;
142
143/* ITU resolution definition */
144struct itu_res {
145 itu_res_id id;
146 pj_str_t name;
147 pjmedia_rect_size size;
148} itu_res_def [] =
149{
150 {ITU_RES_16CIF, {"16CIF",5}, {1408,1142}},
151 {ITU_RES_4CIF, {"4CIF",4}, {704,576}},
152 {ITU_RES_CIF, {"CIF",3}, {352,288}},
153 {ITU_RES_QCIF, {"QCIF",4}, {176,144}},
154 {ITU_RES_SQCIF, {"SQCIF",5}, {88,72}},
155 {ITU_RES_CUSTOM, {"CUSTOM",6}, {0,0}},
156};
157
Benny Prijonoc45d9512010-12-10 11:04:30 +0000158/* FFMPEG codecs private data. */
159typedef struct ffmpeg_private {
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000160 const ffmpeg_codec_desc *desc;
161 pjmedia_vid_codec_param param; /**< Codec param */
162 pj_pool_t *pool; /**< Pool for each instance */
163 pj_timestamp last_tx; /**< Timestamp of last
164 transmit */
165
166 /* Format info and apply format param */
167 const pjmedia_video_format_info *enc_vfi;
168 pjmedia_video_apply_fmt_param enc_vafp;
169 const pjmedia_video_format_info *dec_vfi;
170 pjmedia_video_apply_fmt_param dec_vafp;
171
172 /* The ffmpeg codec states. */
173 AVCodec *enc;
174 AVCodec *dec;
175 AVCodecContext *enc_ctx;
176 AVCodecContext *dec_ctx;
177
178 /* The ffmpeg decoder cannot set the output format, so format conversion
179 * may be needed for post-decoding.
180 */
181 enum PixelFormat expected_dec_fmt;
182 /**< expected output format of
183 ffmpeg decoder */
184 struct SwsContext *sws_ctx; /**< the format converter for
185 post decoding */
186
187} ffmpeg_private;
188
189
190typedef pj_status_t (*func_packetize) (pj_uint8_t *buf,
191 pj_size_t buf_len,
192 unsigned *pos,
193 int max_payload_len,
194 const pj_uint8_t **payload,
195 pj_size_t *payload_len);
196
197typedef pj_status_t (*func_unpacketize) (const pj_uint8_t *payload,
198 pj_size_t payload_len,
199 pj_uint8_t *bits,
200 pj_size_t *bits_len);
201
202typedef pj_status_t (*func_parse_fmtp) (ffmpeg_private *ff);
203
204/* FFMPEG codec info */
205struct ffmpeg_codec_desc {
206 /* Predefined info */
207 pjmedia_vid_codec_info info;
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000208 pjmedia_format_id base_fmt_id;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000209 func_packetize packetize;
210 func_unpacketize unpacketize;
211 func_parse_fmtp parse_fmtp;
212 pjmedia_codec_fmtp dec_fmtp;
213
214 /* Init time defined info */
215 pj_bool_t enabled;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000216 AVCodec *enc;
217 AVCodec *dec;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000218};
Benny Prijonoc45d9512010-12-10 11:04:30 +0000219
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000220/* H263 packetizer */
221static pj_status_t h263_packetize(pj_uint8_t *buf,
222 pj_size_t buf_len,
223 unsigned *pos,
224 int max_payload_len,
225 const pj_uint8_t **payload,
226 pj_size_t *payload_len)
227{
228 return pjmedia_h263_packetize(buf, buf_len, pos, max_payload_len,
229 payload, payload_len);
230}
Benny Prijonoc45d9512010-12-10 11:04:30 +0000231
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000232/* H263 unpacketizer */
233static pj_status_t h263_unpacketize(const pj_uint8_t *payload,
234 pj_size_t payload_len,
235 pj_uint8_t *bits,
236 pj_size_t *bits_len)
237{
238 return pjmedia_h263_unpacketize(payload, payload_len, bits, bits_len);
239}
240
241/* H263 fmtp parser */
242static pj_status_t h263_parse_fmtp(ffmpeg_private *ff);
243
244
245/* Internal codec info */
246ffmpeg_codec_desc codec_desc[] =
247{
248 {
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000249 {PJMEDIA_FORMAT_H263P, {"H263-1998",9}, PJMEDIA_RTP_PT_H263},
250 PJMEDIA_FORMAT_H263,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000251 &h263_packetize, &h263_unpacketize, &h263_parse_fmtp,
252 {2, { {{"CIF",3}, {"2",1}}, {{"QCIF",4}, {"1",1}}, } },
253 },
254 {
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000255 {PJMEDIA_FORMAT_H263, {"H263",4}, PJMEDIA_RTP_PT_H263},
256 0,
257 &h263_packetize, &h263_unpacketize, &h263_parse_fmtp,
258 {2, { {{"CIF",3}, {"2",1}}, {{"QCIF",4}, {"1",1}}, } },
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000259 },
260 {
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000261 {PJMEDIA_FORMAT_H261, {"H261",4}, PJMEDIA_RTP_PT_H261},
262 },
263 {
264 {PJMEDIA_FORMAT_MJPEG, {"JPEG",4}, PJMEDIA_RTP_PT_JPEG},
265 },
266 {
267 {PJMEDIA_FORMAT_MPEG4, {"MP4V",4}, PJMEDIA_RTP_PT_MPV},
268 },
269 {
270 {PJMEDIA_FORMAT_XVID, {"XVID",4}, PJMEDIA_RTP_PT_MPV},
271 PJMEDIA_FORMAT_MPEG4,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000272 },
273};
274
275/* Parse fmtp value for custom resolution, e.g: "CUSTOM=800,600,2" */
276static pj_status_t parse_fmtp_itu_custom_res(const pj_str_t *fmtp_val,
277 pjmedia_rect_size *size,
278 unsigned *mpi)
279{
280 const char *p, *p_end;
281 pj_str_t token;
282 unsigned long val[3] = {0};
283 unsigned i = 0;
284
285 p = token.ptr = fmtp_val->ptr;
286 p_end = p + fmtp_val->slen;
287
288 while (p<=p_end && i<PJ_ARRAY_SIZE(val)) {
289 if (*p==',' || p==p_end) {
290 token.slen = (char*)p - token.ptr;
291 val[i++] = pj_strtoul(&token);
292 token.ptr = (char*)p+1;
293 }
294 ++p;
295 }
296
297 if (!val[0] || !val[1])
298 return PJ_ETOOSMALL;
299
300 if (val[2]<1 || val[2]>32)
301 return PJ_EINVAL;
302
303 size->w = val[0];
304 size->h = val[1];
305 *mpi = val[2];
306 return PJ_SUCCESS;
307}
308
309#define CALC_ITU_CUSTOM_RES_SCORE(size, mpi) ((size)->w * (size)->h / mpi)
310
311/* ITU codec capabilities */
312typedef struct itu_cap
313{
314 /* Lowest MPI for each non-custom resolution */
315 unsigned lowest_mpi[PJ_ARRAY_SIZE(itu_res_def)];
316 /* For custom resolution, we use maximum processing score */
317 unsigned custom_res_max_score;
318} itu_cap;
319
320
321static pj_status_t load_itu_cap(const pjmedia_codec_fmtp *fmtp,
322 itu_cap *cap)
323{
324 unsigned i, j;
325 unsigned min_mpi = 0;
326
327 /* Get Minimum Picture Interval (MPI) for each resolution. If a resolution
328 * has no MPI setting in fmtp, the MPI setting is derived from the higher
329 * resolution.
330 */
331 for (i=0; i<PJ_ARRAY_SIZE(itu_res_def); ++i) {
332
333 /* Init lowest MPI */
334 cap->lowest_mpi[i] = min_mpi? min_mpi:1;
335
336 for (j=0; j<fmtp->cnt; ++j) {
337 if (pj_stricmp(&fmtp->param[j].name, &itu_res_def[i].name)==0) {
338 pjmedia_rect_size size;
339 unsigned mpi;
340 unsigned score;
341
342 if (i != ITU_RES_CUSTOM) {
343 size = itu_res_def[i].size;
344 mpi = pj_strtoul(&fmtp->param[j].val);
345 if (min_mpi)
346 min_mpi = PJ_MIN(mpi, min_mpi);
347 else
348 min_mpi = mpi;
349
350 /* Update the lowest MPI for this resolution */
351 cap->lowest_mpi[i] = min_mpi;
352
353 /* Also update the processing score for the custom
354 * resolution.
355 */
356 score = CALC_ITU_CUSTOM_RES_SCORE(&size, mpi);
357 cap->custom_res_max_score =
358 PJ_MAX(score, cap->custom_res_max_score);
359 } else {
360
361
362 if (parse_fmtp_itu_custom_res(&fmtp->param[j].val,
363 &size, &mpi) == PJ_SUCCESS)
364 {
365 score = CALC_ITU_CUSTOM_RES_SCORE(&size, mpi);
366 cap->custom_res_max_score =
367 PJ_MAX(score, cap->custom_res_max_score);
368 }
369 }
370 }
371 }
372 }
373
374 return PJ_SUCCESS;
375}
376
377/* H263 fmtp parser */
378static pj_status_t h263_parse_fmtp(ffmpeg_private *ff)
379{
380 pjmedia_dir dir;
381 pj_status_t status;
382
383 dir = ff->param.dir;
384
385 if (ff->param.dir & PJMEDIA_DIR_ENCODING) {
386 pjmedia_vid_codec_param param_ref;
387 pjmedia_codec_fmtp *fmtp_rem, *fmtp_ref;
388 itu_cap local_cap;
389 pjmedia_rect_size size = {0};
390 unsigned mpi = 0;
391 pj_bool_t got_good_res = PJ_FALSE;
392 pj_bool_t has_prefered_res = PJ_FALSE;
393 unsigned i, j;
394
395 fmtp_rem = &ff->param.enc_fmtp;
396 dir &= ~PJMEDIA_DIR_ENCODING;
397
398 /* Get default fmtp setting as the reference for local capabilities */
399 status = pjmedia_vid_codec_mgr_get_default_param(
400 ffmpeg_factory.mgr, &ff->desc->info, &param_ref);
401 fmtp_ref = (status==PJ_SUCCESS)? &param_ref.enc_fmtp : fmtp_rem;
402
403 /* Load default local capabilities */
404 status = load_itu_cap(fmtp_ref, &local_cap);
405 pj_assert(status == PJ_SUCCESS);
406
407 /* Negotiate resolution and MPI */
408 for (i=0; i<fmtp_rem->cnt && !got_good_res; ++i)
409 {
410 for (j=0; j<PJ_ARRAY_SIZE(itu_res_def) && !got_good_res; ++j)
411 {
412 if (pj_stricmp(&fmtp_rem->param[i].name, &itu_res_def[j].name))
413 continue;
414
415 has_prefered_res = PJ_TRUE;
416 if (j == ITU_RES_CUSTOM) {
417 unsigned score;
418
419 if (parse_fmtp_itu_custom_res(&fmtp_rem->param[i].val,
420 &size, &mpi) != PJ_SUCCESS)
421 {
422 /* Invalid custom resolution format, skip this
423 * custom resolution
424 */
425 break;
426 }
427
428 score = CALC_ITU_CUSTOM_RES_SCORE(&size, mpi);
429 if (score <= local_cap.custom_res_max_score)
430 got_good_res = PJ_TRUE;
431 } else {
432 mpi = pj_strtoul(&fmtp_rem->param[i].val);
433 if (mpi>=1 && mpi<=32 && mpi>=local_cap.lowest_mpi[j]) {
434 got_good_res = PJ_TRUE;
435 size = itu_res_def[j].size;
436 }
437 }
438 }
439 }
440
441 if (has_prefered_res) {
442 if (got_good_res) {
443 pjmedia_video_format_detail *vfd;
444
445 /* Apply this size & MPI */
446 vfd = pjmedia_format_get_video_format_detail(&ff->param.enc_fmt,
447 PJ_TRUE);
448 vfd->size = size;
449 vfd->fps.num = 30000;
450 vfd->fps.denum = 1001 * mpi;
451 got_good_res = PJ_TRUE;
452
453 PJ_TODO(NOTIFY_APP_ABOUT_THIS_NEW_ENCODING_FORMAT);
454 } else {
455 return PJ_EUNKNOWN;
456 }
457 }
458 }
459
460 return PJ_SUCCESS;
461}
462
463
464
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000465static const ffmpeg_codec_desc* find_codec_desc_by_info(
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000466 const pjmedia_vid_codec_info *info)
467{
468 int i;
469
470 for (i=0; i<PJ_ARRAY_SIZE(codec_desc); ++i) {
471 ffmpeg_codec_desc *desc = &codec_desc[i];
472
473 if (desc->enabled &&
474 (desc->info.fmt_id == info->fmt_id) &&
475 ((desc->info.dir & info->dir) == info->dir) &&
476 pj_stricmp(&desc->info.encoding_name, &info->encoding_name)==0)
477 {
478 return desc;
479 }
480 }
481
482 return NULL;
483}
484
485
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000486static int find_codec_idx_by_fmt_id(pjmedia_format_id fmt_id)
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000487{
488 int i;
489 for (i=0; i<PJ_ARRAY_SIZE(codec_desc); ++i) {
490 if (codec_desc[i].info.fmt_id == fmt_id)
491 return i;
492 }
493
494 return -1;
495}
Benny Prijonoc45d9512010-12-10 11:04:30 +0000496
497
498/*
499 * Initialize and register FFMPEG codec factory to pjmedia endpoint.
500 */
501PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_init(pjmedia_vid_codec_mgr *mgr,
502 pj_pool_factory *pf)
503{
504 pj_pool_t *pool;
505 AVCodec *c;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000506 pj_status_t status;
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000507 unsigned i;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000508
509 if (ffmpeg_factory.pool != NULL) {
510 /* Already initialized. */
511 return PJ_SUCCESS;
512 }
513
514 if (!mgr) mgr = pjmedia_vid_codec_mgr_instance();
515 PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
516
517 /* Create FFMPEG codec factory. */
518 ffmpeg_factory.base.op = &ffmpeg_factory_op;
519 ffmpeg_factory.base.factory_data = NULL;
520 ffmpeg_factory.mgr = mgr;
521 ffmpeg_factory.pf = pf;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000522
523 pool = pj_pool_create(pf, "ffmpeg codec factory", 256, 256, NULL);
524 if (!pool)
525 return PJ_ENOMEM;
526
527 /* Create mutex. */
528 status = pj_mutex_create_simple(pool, "ffmpeg codec factory",
529 &ffmpeg_factory.mutex);
530 if (status != PJ_SUCCESS)
531 goto on_error;
532
533 avcodec_init();
534 avcodec_register_all();
535
536 /* Enum FFMPEG codecs */
537 for (c=av_codec_next(NULL); c; c=av_codec_next(c))
538 {
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000539 ffmpeg_codec_desc *desc;
540 pjmedia_format_id fmt_id;
541 int codec_info_idx;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000542
543 if (c->type != CODEC_TYPE_VIDEO)
544 continue;
545
546 /* Video encoder and decoder are usually implemented in separate
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000547 * AVCodec instances. While the codec attributes (e.g: raw formats,
548 * supported fps) are in the encoder.
Benny Prijonoc45d9512010-12-10 11:04:30 +0000549 */
550
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000551 //PJ_LOG(3, (THIS_FILE, "%s", c->name));
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000552 status = CodecID_to_pjmedia_format_id(c->id, &fmt_id);
553 /* Skip if format ID is unknown */
554 if (status != PJ_SUCCESS)
555 continue;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000556
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000557 codec_info_idx = find_codec_idx_by_fmt_id(fmt_id);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000558 /* Skip if codec is unwanted by this wrapper (not listed in
559 * the codec info array)
560 */
561 if (codec_info_idx < 0)
562 continue;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000563
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000564 desc = &codec_desc[codec_info_idx];
Benny Prijonoc45d9512010-12-10 11:04:30 +0000565
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000566 /* Skip duplicated codec implementation */
567 if ((c->encode && (desc->info.dir & PJMEDIA_DIR_ENCODING)) ||
568 (c->decode && (desc->info.dir & PJMEDIA_DIR_DECODING)))
569 {
570 continue;
571 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000572
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000573 /* Get raw/decoded format ids in the encoder */
574 if (c->pix_fmts && c->encode) {
575 pjmedia_format_id raw_fmt[PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT];
576 unsigned raw_fmt_cnt = 0;
577 unsigned raw_fmt_cnt_should_be = 0;
578 const enum PixelFormat *p = c->pix_fmts;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000579
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000580 for(;(p && *p != -1) &&
581 (raw_fmt_cnt < PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT);
582 ++p)
583 {
584 pjmedia_format_id fmt_id;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000585
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000586 raw_fmt_cnt_should_be++;
587 status = PixelFormat_to_pjmedia_format_id(*p, &fmt_id);
588 if (status != PJ_SUCCESS) {
589 PJ_LOG(6, (THIS_FILE, "Unrecognized ffmpeg pixel "
590 "format %d", *p));
591 continue;
592 }
593 raw_fmt[raw_fmt_cnt++] = fmt_id;
594 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000595
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000596 if (raw_fmt_cnt == 0) {
597 PJ_LOG(5, (THIS_FILE, "No recognized raw format "
598 "for codec [%s/%s], codec ignored",
599 c->name, c->long_name));
600 /* Skip this encoder */
601 continue;
602 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000603
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000604 if (raw_fmt_cnt < raw_fmt_cnt_should_be) {
605 PJ_LOG(6, (THIS_FILE, "Codec [%s/%s] have %d raw formats, "
606 "recognized only %d raw formats",
607 c->name, c->long_name,
608 raw_fmt_cnt_should_be, raw_fmt_cnt));
609 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000610
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000611 desc->info.dec_fmt_id_cnt = raw_fmt_cnt;
612 pj_memcpy(desc->info.dec_fmt_id, raw_fmt,
613 sizeof(raw_fmt[0])*raw_fmt_cnt);
614 }
615
616 /* Get supported framerates */
617 if (c->supported_framerates) {
618 const AVRational *fr = c->supported_framerates;
619 while ((fr->num != 0 || fr->den != 0) &&
620 desc->info.fps_cnt < PJMEDIA_VID_CODEC_MAX_FPS_CNT)
621 {
622 desc->info.fps[desc->info.fps_cnt].num = fr->num;
623 desc->info.fps[desc->info.fps_cnt].denum = fr->den;
624 ++desc->info.fps_cnt;
625 ++fr;
626 }
627 }
628
629 /* Get ffmpeg encoder instance */
630 if (c->encode && !desc->enc) {
631 desc->info.dir |= PJMEDIA_DIR_ENCODING;
632 desc->enc = c;
633 }
634
635 /* Get ffmpeg decoder instance */
636 if (c->decode && !desc->dec) {
637 desc->info.dir |= PJMEDIA_DIR_DECODING;
638 desc->dec = c;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000639 }
640
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000641 /* Enable this codec when any ffmpeg codec instance are recognized
642 * and the supported raw formats info has been collected.
643 */
644 if ((desc->dec || desc->enc) && desc->info.dec_fmt_id_cnt)
645 {
646 desc->enabled = PJ_TRUE;
647 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000648
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000649 /* Normalize default value of clock rate */
650 if (desc->info.clock_rate == 0)
651 desc->info.clock_rate = 90000;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000652 }
653
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000654 /* Init unassigned encoder/decoder description from base codec */
655 for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
656 ffmpeg_codec_desc *desc = &codec_desc[i];
657
658 if (desc->base_fmt_id && (!desc->dec || !desc->enc)) {
659 ffmpeg_codec_desc *base_desc = NULL;
660 int base_desc_idx;
661 pjmedia_dir copied_dir = PJMEDIA_DIR_NONE;
662
663 base_desc_idx = find_codec_idx_by_fmt_id(desc->base_fmt_id);
664 if (base_desc_idx != -1)
665 base_desc = &codec_desc[base_desc_idx];
666 if (!base_desc || !base_desc->enabled)
667 continue;
668
669 /* Copy description from base codec */
670 if (!desc->info.dec_fmt_id_cnt) {
671 desc->info.dec_fmt_id_cnt = base_desc->info.dec_fmt_id_cnt;
672 pj_memcpy(desc->info.dec_fmt_id, base_desc->info.dec_fmt_id,
673 sizeof(pjmedia_format_id)*desc->info.dec_fmt_id_cnt);
674 }
675 if (!desc->info.fps_cnt) {
676 desc->info.fps_cnt = base_desc->info.fps_cnt;
677 pj_memcpy(desc->info.fps, base_desc->info.fps,
678 sizeof(desc->info.fps[0])*desc->info.fps_cnt);
679 }
680 if (!desc->info.clock_rate) {
681 desc->info.clock_rate = base_desc->info.clock_rate;
682 }
683 if (!desc->dec && base_desc->dec) {
684 copied_dir |= PJMEDIA_DIR_DECODING;
685 desc->dec = base_desc->dec;
686 }
687 if (!desc->enc && base_desc->enc) {
688 copied_dir |= PJMEDIA_DIR_ENCODING;
689 desc->enc = base_desc->enc;
690 }
691
692 desc->info.dir |= copied_dir;
693 desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE);
694
695 if (copied_dir != PJMEDIA_DIR_NONE) {
696 const char *dir_name[] = {NULL, "encoder", "decoder", "codec"};
697 PJ_LOG(5, (THIS_FILE, "The %.*s %s is using base codec (%.*s)",
698 desc->info.encoding_name.slen,
699 desc->info.encoding_name.ptr,
700 dir_name[copied_dir],
701 base_desc->info.encoding_name.slen,
702 base_desc->info.encoding_name.ptr));
703 }
704 }
705 }
706
Benny Prijonoc45d9512010-12-10 11:04:30 +0000707 /* Register codec factory to codec manager. */
708 status = pjmedia_vid_codec_mgr_register_factory(mgr,
709 &ffmpeg_factory.base);
710 if (status != PJ_SUCCESS)
711 goto on_error;
712
713 ffmpeg_factory.pool = pool;
714
715 /* Done. */
716 return PJ_SUCCESS;
717
718on_error:
719 pj_pool_release(pool);
720 return status;
721}
722
723/*
724 * Unregister FFMPEG codecs factory from pjmedia endpoint.
725 */
726PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_deinit(void)
727{
728 pj_status_t status = PJ_SUCCESS;
729
730 if (ffmpeg_factory.pool == NULL) {
731 /* Already deinitialized */
732 return PJ_SUCCESS;
733 }
734
735 pj_mutex_lock(ffmpeg_factory.mutex);
736
737 /* Unregister FFMPEG codecs factory. */
738 status = pjmedia_vid_codec_mgr_unregister_factory(ffmpeg_factory.mgr,
739 &ffmpeg_factory.base);
740
741 /* Destroy mutex. */
742 pj_mutex_destroy(ffmpeg_factory.mutex);
743
744 /* Destroy pool. */
745 pj_pool_release(ffmpeg_factory.pool);
746 ffmpeg_factory.pool = NULL;
747
748 return status;
749}
750
751
Benny Prijonoc45d9512010-12-10 11:04:30 +0000752/*
753 * Check if factory can allocate the specified codec.
754 */
755static pj_status_t ffmpeg_test_alloc( pjmedia_vid_codec_factory *factory,
756 const pjmedia_vid_codec_info *info )
757{
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000758 const ffmpeg_codec_desc *desc;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000759
760 PJ_ASSERT_RETURN(factory==&ffmpeg_factory.base, PJ_EINVAL);
761 PJ_ASSERT_RETURN(info, PJ_EINVAL);
762
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000763 desc = find_codec_desc_by_info(info);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000764 if (!desc) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000765 return PJMEDIA_CODEC_EUNSUP;
766 }
767
768 return PJ_SUCCESS;
769}
770
771/*
772 * Generate default attribute.
773 */
774static pj_status_t ffmpeg_default_attr( pjmedia_vid_codec_factory *factory,
775 const pjmedia_vid_codec_info *info,
776 pjmedia_vid_codec_param *attr )
777{
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000778 const ffmpeg_codec_desc *desc;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000779
780 PJ_ASSERT_RETURN(factory==&ffmpeg_factory.base, PJ_EINVAL);
781 PJ_ASSERT_RETURN(info && attr, PJ_EINVAL);
782
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000783 desc = find_codec_desc_by_info(info);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000784 if (!desc) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000785 return PJMEDIA_CODEC_EUNSUP;
786 }
787
788 pj_bzero(attr, sizeof(pjmedia_vid_codec_param));
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000789
790 /* Direction */
791 attr->dir = desc->info.dir;
792
793 /* Encoded format */
794 pjmedia_format_init_video(&attr->enc_fmt, desc->info.fmt_id,
795 352, 288, 30000, 1001);
796
797 /* Decoded format */
798 pjmedia_format_init_video(&attr->dec_fmt, desc->info.dec_fmt_id[0],
799 352, 288, 30000, 1001);
800
801 /* Decoding fmtp */
802 attr->dec_fmtp = desc->dec_fmtp;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000803
804 return PJ_SUCCESS;
805}
806
807/*
808 * Enum codecs supported by this factory.
809 */
810static pj_status_t ffmpeg_enum_codecs( pjmedia_vid_codec_factory *factory,
811 unsigned *count,
812 pjmedia_vid_codec_info codecs[])
813{
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000814 unsigned i, max_cnt;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000815
816 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
817 PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
818
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000819 max_cnt = PJ_MIN(*count, PJ_ARRAY_SIZE(codec_desc));
820 *count = 0;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000821
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000822 for (i=0; i<max_cnt; ++i) {
823 if (codec_desc[i].enabled) {
824 pj_memcpy(&codecs[*count], &codec_desc[i].info,
825 sizeof(pjmedia_vid_codec_info));
826 (*count)++;
827 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000828 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000829
830 return PJ_SUCCESS;
831}
832
833/*
834 * Allocate a new codec instance.
835 */
836static pj_status_t ffmpeg_alloc_codec( pjmedia_vid_codec_factory *factory,
837 const pjmedia_vid_codec_info *info,
838 pjmedia_vid_codec **p_codec)
839{
840 ffmpeg_private *ff;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000841 const ffmpeg_codec_desc *desc;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000842 pjmedia_vid_codec *codec;
843 pj_pool_t *pool = NULL;
844 pj_status_t status = PJ_SUCCESS;
845
846 PJ_ASSERT_RETURN(factory && info && p_codec, PJ_EINVAL);
847 PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
848
Nanang Izzuddin235e1b42011-02-28 18:59:47 +0000849 desc = find_codec_desc_by_info(info);
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000850 if (!desc) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000851 return PJMEDIA_CODEC_EUNSUP;
852 }
853
854 /* Create pool for codec instance */
855 pool = pj_pool_create(ffmpeg_factory.pf, "ffmpeg codec", 512, 512, NULL);
856 codec = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec);
857 if (!codec) {
858 status = PJ_ENOMEM;
859 goto on_error;
860 }
861 codec->op = &ffmpeg_op;
862 codec->factory = factory;
863 ff = PJ_POOL_ZALLOC_T(pool, ffmpeg_private);
864 if (!ff) {
865 status = PJ_ENOMEM;
866 goto on_error;
867 }
868 codec->codec_data = ff;
869 ff->pool = pool;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000870 ff->enc = desc->enc;
871 ff->dec = desc->dec;
872 ff->desc = desc;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000873
874 *p_codec = codec;
875 return PJ_SUCCESS;
876
877on_error:
878 if (pool)
879 pj_pool_release(pool);
880 return status;
881}
882
883/*
884 * Free codec.
885 */
886static pj_status_t ffmpeg_dealloc_codec( pjmedia_vid_codec_factory *factory,
887 pjmedia_vid_codec *codec )
888{
889 ffmpeg_private *ff;
890 pj_pool_t *pool;
891
892 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
893 PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
894
895 /* Close codec, if it's not closed. */
896 ff = (ffmpeg_private*) codec->codec_data;
897 pool = ff->pool;
898 codec->codec_data = NULL;
899 pj_pool_release(pool);
900
901 return PJ_SUCCESS;
902}
903
904/*
905 * Init codec.
906 */
907static pj_status_t ffmpeg_codec_init( pjmedia_vid_codec *codec,
908 pj_pool_t *pool )
909{
910 PJ_UNUSED_ARG(codec);
911 PJ_UNUSED_ARG(pool);
912 return PJ_SUCCESS;
913}
914
915static void print_ffmpeg_err(int err)
916{
917#if LIBAVCODEC_VERSION_MAJOR >= 52 && LIBAVCODEC_VERSION_MINOR >= 72
918 char errbuf[512];
919 if (av_strerror(err, errbuf, sizeof(errbuf)) >= 0)
920 PJ_LOG(1, (THIS_FILE, "ffmpeg err %d: %s", err, errbuf));
921#else
922 PJ_LOG(1, (THIS_FILE, "ffmpeg err %d", err));
923#endif
924
925}
926
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000927static enum PixelFormat dec_get_format(struct AVCodecContext *s,
Benny Prijonoc45d9512010-12-10 11:04:30 +0000928 const enum PixelFormat * fmt)
929{
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000930 ffmpeg_private *ff = (ffmpeg_private*)s->opaque;
931 enum PixelFormat def_fmt = *fmt;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000932
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000933 while (*fmt != -1) {
934 if (*fmt == ff->expected_dec_fmt)
935 return *fmt;
936 ++fmt;
937 }
Benny Prijonoc45d9512010-12-10 11:04:30 +0000938
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000939 pj_assert(!"Inconsistency in supported formats");
940 return def_fmt;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000941}
942
Benny Prijonoc45d9512010-12-10 11:04:30 +0000943
944static pj_status_t open_ffmpeg_codec(ffmpeg_private *ff,
945 pj_mutex_t *ff_mutex)
946{
947 enum PixelFormat pix_fmt;
948 pj_status_t status;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000949 pjmedia_video_format_detail *vfd;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000950
951 status = pjmedia_format_id_to_PixelFormat(ff->param.dec_fmt.id,
952 &pix_fmt);
953 if (status != PJ_SUCCESS)
954 return status;
955
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000956 vfd = pjmedia_format_get_video_format_detail(&ff->param.enc_fmt,
957 PJ_TRUE);
958 ff->expected_dec_fmt = pix_fmt;
959
Benny Prijonoc45d9512010-12-10 11:04:30 +0000960 while (((ff->param.dir & PJMEDIA_DIR_ENCODING) && ff->enc_ctx == NULL) ||
961 ((ff->param.dir & PJMEDIA_DIR_DECODING) && ff->dec_ctx == NULL))
962 {
963 pjmedia_dir dir;
964 AVCodecContext *ctx = NULL;
965 AVCodec *codec = NULL;
966 int err;
967
968 /* Set which direction to open */
969 if (ff->param.dir==PJMEDIA_DIR_ENCODING_DECODING && ff->enc!=ff->dec) {
970 dir = ff->enc_ctx? PJMEDIA_DIR_DECODING : PJMEDIA_DIR_ENCODING;
971 } else {
972 dir = ff->param.dir;
973 }
974
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000975 /* Init ffmpeg codec context */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000976 ctx = avcodec_alloc_context();
977
978 /* Common attributes */
979 ctx->pix_fmt = pix_fmt;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000980 ctx->workaround_bugs = FF_BUG_AUTODETECT;
981 ctx->opaque = ff;
982
983 if (dir & PJMEDIA_DIR_ENCODING) {
984 codec = ff->enc;
985
986 /* Encoding only attributes */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000987 ctx->width = vfd->size.w;
988 ctx->height = vfd->size.h;
989 ctx->time_base.num = vfd->fps.denum;
990 ctx->time_base.den = vfd->fps.num;
991 if (vfd->avg_bps)
992 ctx->bit_rate = vfd->avg_bps;
993 if (vfd->max_bps)
994 ctx->rc_max_rate = vfd->max_bps;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000995
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000996 /* For encoder, should be better to be strict to the standards */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000997 ctx->strict_std_compliance = FF_COMPLIANCE_STRICT;
998 }
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +0000999
Benny Prijonoc45d9512010-12-10 11:04:30 +00001000 if (dir & PJMEDIA_DIR_DECODING) {
1001 codec = ff->dec;
1002
1003 /* Decoding only attributes */
Nanang Izzuddin235e1b42011-02-28 18:59:47 +00001004
1005 /* Width/height may be overriden by ffmpeg after first decoding. */
1006 ctx->width = ctx->coded_width = ff->param.dec_fmt.det.vid.size.w;
1007 ctx->height = ctx->coded_height = ff->param.dec_fmt.det.vid.size.h;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001008
1009 /* For decoder, be more flexible */
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001010 if (ff->param.dir!=PJMEDIA_DIR_ENCODING_DECODING ||
1011 ff->enc!=ff->dec)
1012 {
Benny Prijonoc45d9512010-12-10 11:04:30 +00001013 ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001014 }
Benny Prijonoc45d9512010-12-10 11:04:30 +00001015
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001016 ctx->get_format = &dec_get_format;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001017 }
1018
1019 /* avcodec_open() should be protected */
1020 pj_mutex_lock(ff_mutex);
1021 err = avcodec_open(ctx, codec);
1022 pj_mutex_unlock(ff_mutex);
1023 if (err < 0) {
1024 print_ffmpeg_err(err);
1025 return PJ_EUNKNOWN;
1026 }
1027
1028 if (dir & PJMEDIA_DIR_ENCODING)
1029 ff->enc_ctx = ctx;
1030 if (dir & PJMEDIA_DIR_DECODING)
1031 ff->dec_ctx = ctx;
1032 }
1033
1034 return PJ_SUCCESS;
1035}
1036
1037/*
1038 * Open codec.
1039 */
1040static pj_status_t ffmpeg_codec_open( pjmedia_vid_codec *codec,
1041 pjmedia_vid_codec_param *attr )
1042{
1043 ffmpeg_private *ff;
1044 pj_status_t status;
1045 pj_mutex_t *ff_mutex;
1046
1047 PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
1048 ff = (ffmpeg_private*)codec->codec_data;
1049
Benny Prijonoc45d9512010-12-10 11:04:30 +00001050 pj_memcpy(&ff->param, attr, sizeof(*attr));
1051
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001052 /* Apply SDP fmtp attribute */
1053 if (ff->desc->parse_fmtp) {
1054 status = (*ff->desc->parse_fmtp)(ff);
1055 if (status != PJ_SUCCESS)
1056 goto on_error;
1057 }
1058
1059 /* Open the codec */
Benny Prijonoc45d9512010-12-10 11:04:30 +00001060 ff_mutex = ((struct ffmpeg_factory*)codec->factory)->mutex;
1061 status = open_ffmpeg_codec(ff, ff_mutex);
1062 if (status != PJ_SUCCESS)
1063 goto on_error;
1064
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001065 /* Init format info and apply-param of decoder */
1066 ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
1067 if (!ff->dec_vfi) {
1068 status = PJ_EINVAL;
1069 goto on_error;
1070 }
1071 pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
1072 ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
1073 ff->dec_vafp.buffer = NULL;
1074 status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
1075 if (status != PJ_SUCCESS) {
1076 goto on_error;
1077 }
1078
1079 /* Init format info and apply-param of encoder */
1080 ff->enc_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
1081 if (!ff->enc_vfi) {
1082 status = PJ_EINVAL;
1083 goto on_error;
1084 }
1085 pj_bzero(&ff->enc_vafp, sizeof(ff->enc_vafp));
1086 ff->enc_vafp.size = ff->param.enc_fmt.det.vid.size;
1087 ff->enc_vafp.buffer = NULL;
1088 status = (*ff->enc_vfi->apply_fmt)(ff->enc_vfi, &ff->enc_vafp);
1089 if (status != PJ_SUCCESS) {
1090 goto on_error;
1091 }
1092
1093 /* Update codec attributes, e.g: encoding format may be changed by
1094 * SDP fmtp negotiation.
1095 */
1096 pj_memcpy(attr, &ff->param, sizeof(*attr));
1097
Benny Prijonoc45d9512010-12-10 11:04:30 +00001098 return PJ_SUCCESS;
1099
1100on_error:
1101 ffmpeg_codec_close(codec);
1102 return status;
1103}
1104
1105/*
1106 * Close codec.
1107 */
1108static pj_status_t ffmpeg_codec_close( pjmedia_vid_codec *codec )
1109{
1110 ffmpeg_private *ff;
1111 pj_mutex_t *ff_mutex;
1112
1113 PJ_ASSERT_RETURN(codec, PJ_EINVAL);
1114 ff = (ffmpeg_private*)codec->codec_data;
1115 ff_mutex = ((struct ffmpeg_factory*)codec->factory)->mutex;
1116
1117 pj_mutex_lock(ff_mutex);
1118 if (ff->enc_ctx) {
1119 avcodec_close(ff->enc_ctx);
1120 av_free(ff->enc_ctx);
1121 }
1122 if (ff->dec_ctx && ff->dec_ctx!=ff->enc_ctx) {
1123 avcodec_close(ff->dec_ctx);
1124 av_free(ff->dec_ctx);
1125 }
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001126 if (ff->sws_ctx) {
1127 sws_freeContext(ff->sws_ctx);
Benny Prijonoc45d9512010-12-10 11:04:30 +00001128 }
1129 ff->enc_ctx = NULL;
1130 ff->dec_ctx = NULL;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001131 ff->sws_ctx = NULL;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001132 pj_mutex_unlock(ff_mutex);
1133
1134 return PJ_SUCCESS;
1135}
1136
1137
1138/*
1139 * Modify codec settings.
1140 */
1141static pj_status_t ffmpeg_codec_modify( pjmedia_vid_codec *codec,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001142 const pjmedia_vid_codec_param *attr)
Benny Prijonoc45d9512010-12-10 11:04:30 +00001143{
1144 ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
1145
1146 PJ_UNUSED_ARG(attr);
1147 PJ_UNUSED_ARG(ff);
1148
1149 return PJ_ENOTSUP;
1150}
1151
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001152static pj_status_t ffmpeg_codec_get_param(pjmedia_vid_codec *codec,
1153 pjmedia_vid_codec_param *param)
1154{
1155 ffmpeg_private *ff;
1156
1157 PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
1158
1159 ff = (ffmpeg_private*)codec->codec_data;
1160 pj_memcpy(param, &ff->param, sizeof(*param));
1161
1162 return PJ_SUCCESS;
1163}
1164
1165
Benny Prijonoc45d9512010-12-10 11:04:30 +00001166static pj_status_t ffmpeg_packetize ( pjmedia_vid_codec *codec,
1167 pj_uint8_t *buf,
1168 pj_size_t buf_len,
1169 unsigned *pos,
1170 const pj_uint8_t **payload,
1171 pj_size_t *payload_len)
1172{
1173 ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
1174
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001175 if (ff->desc->packetize) {
1176 return (*ff->desc->packetize)(buf, buf_len, pos,
1177 ff->param.enc_mtu, payload,
1178 payload_len);
Benny Prijonoc45d9512010-12-10 11:04:30 +00001179 }
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001180
1181 return PJ_ENOTSUP;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001182}
1183
1184static pj_status_t ffmpeg_unpacketize(pjmedia_vid_codec *codec,
1185 const pj_uint8_t *payload,
1186 pj_size_t payload_len,
1187 pj_uint8_t *buf,
1188 pj_size_t *buf_len)
1189{
1190 ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
1191
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001192 if (ff->desc->unpacketize) {
1193 return (*ff->desc->unpacketize)(payload, payload_len,
1194 buf, buf_len);
Benny Prijonoc45d9512010-12-10 11:04:30 +00001195 }
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001196
1197 return PJ_ENOTSUP;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001198}
1199
Benny Prijonoc45d9512010-12-10 11:04:30 +00001200
1201/*
1202 * Encode frames.
1203 */
1204static pj_status_t ffmpeg_codec_encode( pjmedia_vid_codec *codec,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001205 const pjmedia_frame *input,
Benny Prijonoc45d9512010-12-10 11:04:30 +00001206 unsigned output_buf_len,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001207 pjmedia_frame *output)
Benny Prijonoc45d9512010-12-10 11:04:30 +00001208{
1209 ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
1210 pj_uint8_t *p = (pj_uint8_t*)input->buf;
1211 AVFrame avframe;
1212 pj_uint8_t *out_buf = (pj_uint8_t*)output->buf;
1213 int out_buf_len = output_buf_len;
1214 int err;
1215 unsigned i;
1216
1217 /* Check if encoder has been opened */
1218 PJ_ASSERT_RETURN(ff->enc_ctx, PJ_EINVALIDOP);
1219
Benny Prijonoc45d9512010-12-10 11:04:30 +00001220 avcodec_get_frame_defaults(&avframe);
1221
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001222 for (i = 0; i < ff->enc_vfi->plane_cnt; ++i) {
Benny Prijonoc45d9512010-12-10 11:04:30 +00001223 avframe.data[i] = p;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001224 avframe.linesize[i] = ff->enc_vafp.strides[i];
1225 p += ff->enc_vafp.plane_bytes[i];
Benny Prijonoc45d9512010-12-10 11:04:30 +00001226 }
1227
1228#ifdef _MSC_VER
1229 /* Align stack for MSVC environment to avoid 'random' crash, as advised in
1230 * http://ffmpeg.arrozcru.org/forum/viewtopic.php?f=1&t=549
1231 */
1232# define VHALIGNCALL16(x) \
1233 {\
1234 _asm { mov ebx, esp }\
1235 _asm { and esp, 0xfffffff0 }\
1236 _asm { sub esp, 12 }\
1237 _asm { push ebx }\
1238 x;\
1239 _asm { pop ebx }\
1240 _asm { mov esp, ebx }\
1241 }
1242#else
1243# define VHALIGNCALL16(x)
1244#endif
1245
1246 VHALIGNCALL16(err = avcodec_encode_video(ff->enc_ctx, out_buf,
1247 out_buf_len, &avframe));
1248
1249 if (err < 0) {
1250 print_ffmpeg_err(err);
1251 return PJ_EUNKNOWN;
1252 } else {
1253 output->size = err;
1254 }
1255
1256 return PJ_SUCCESS;
1257}
1258
1259/*
1260 * Decode frame.
1261 */
1262static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001263 const pjmedia_frame *input,
Benny Prijonoc45d9512010-12-10 11:04:30 +00001264 unsigned output_buf_len,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001265 pjmedia_frame *output)
Benny Prijonoc45d9512010-12-10 11:04:30 +00001266{
1267 ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
1268 AVFrame avframe;
1269 AVPacket avpacket;
1270 int err, got_picture;
1271
1272 /* Check if decoder has been opened */
1273 PJ_ASSERT_RETURN(ff->dec_ctx, PJ_EINVALIDOP);
1274
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001275 /* Validate output buffer size */
Nanang Izzuddin235e1b42011-02-28 18:59:47 +00001276 //PJ_ASSERT_RETURN(ff->dec_vafp.framebytes <= output_buf_len, PJ_ETOOSMALL);
Benny Prijonoc45d9512010-12-10 11:04:30 +00001277
1278 /* Init frame to receive the decoded data, the ffmpeg codec context will
1279 * automatically provide the decoded buffer (single buffer used for the
1280 * whole decoding session, and seems to be freed when the codec context
1281 * closed).
1282 */
1283 avcodec_get_frame_defaults(&avframe);
1284
1285 /* Init packet, the container of the encoded data */
1286 av_init_packet(&avpacket);
1287 avpacket.data = (pj_uint8_t*)input->buf;
1288 avpacket.size = input->size;
1289
1290 /* ffmpeg warns:
1291 * - input buffer padding, at least FF_INPUT_BUFFER_PADDING_SIZE
1292 * - null terminated
1293 * Normally, encoded buffer is allocated more than needed, so lets just
1294 * bzero the input buffer end/pad, hope it will be just fine.
1295 */
1296 pj_bzero(avpacket.data+avpacket.size, FF_INPUT_BUFFER_PADDING_SIZE);
1297
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001298 output->bit_info = 0;
1299
Benny Prijonoc45d9512010-12-10 11:04:30 +00001300#if LIBAVCODEC_VERSION_MAJOR >= 52 && LIBAVCODEC_VERSION_MINOR >= 72
1301 avpacket.flags = AV_PKT_FLAG_KEY;
1302#else
1303 avpacket.flags = 0;
1304#endif
1305
1306#if LIBAVCODEC_VERSION_MAJOR >= 52 && LIBAVCODEC_VERSION_MINOR >= 72
1307 err = avcodec_decode_video2(ff->dec_ctx, &avframe,
1308 &got_picture, &avpacket);
1309#else
1310 err = avcodec_decode_video(ff->dec_ctx, &avframe,
1311 &got_picture, avpacket.data, avpacket.size);
1312#endif
1313 if (err < 0) {
1314 print_ffmpeg_err(err);
1315 return PJ_EUNKNOWN;
1316 } else if (got_picture) {
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001317 pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001318 pj_uint8_t *q = (pj_uint8_t*)output->buf;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001319 unsigned i;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001320
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001321 /* Decoder output format is set by libavcodec, in case it is different
1322 * to the configured param.
1323 */
1324 if (ff->dec_ctx->pix_fmt != ff->expected_dec_fmt ||
1325 ff->dec_ctx->coded_width != (int)vafp->size.w ||
1326 ff->dec_ctx->coded_height != (int)vafp->size.h)
1327 {
1328#if 0
1329 // it should not be the codec responsibility to do resizing
1330 pj_uint8_t *data[PJMEDIA_MAX_VIDEO_PLANES] = {0};
1331 unsigned i;
1332 int h;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001333
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001334 if (!ff->sws_ctx) {
1335 pj_assert(sws_isSupportedInput(ff->dec_ctx->pix_fmt) > 0);
1336 pj_assert(sws_isSupportedOutput(ff->expected_dec_fmt) > 0);
1337 ff->sws_ctx = sws_getContext(ff->dec_ctx->coded_width,
1338 ff->dec_ctx->coded_height,
1339 ff->dec_ctx->pix_fmt,
1340 vafp->size.w, vafp->size.h,
1341 ff->expected_dec_fmt,
1342 SWS_BILINEAR | SWS_PRINT_INFO,
1343 NULL, NULL, NULL);
1344 if (ff->sws_ctx == NULL) {
1345 return PJ_EUNKNOWN;
1346 }
1347 }
1348
1349 for (i = 0; i < ff->vfi->plane_cnt; ++i) {
1350 data[i] = q;
1351 q += vafp->plane_bytes[i];
1352 }
1353 h = sws_scale(ff->sws_ctx, avframe.data, avframe.linesize, 0,
1354 ff->dec_ctx->coded_height, data, vafp->strides);
1355 pj_assert((int)vafp->size.h == h);
1356#endif
1357
1358 pjmedia_format_id new_fmt_id;
1359 pj_status_t status;
1360
1361 /* Get current raw format id from ffmpeg decoder context */
1362 status = PixelFormat_to_pjmedia_format_id(ff->dec_ctx->pix_fmt,
1363 &new_fmt_id);
1364 if (status != PJ_SUCCESS)
1365 return status;
1366
1367 /* Update decoder format in param */
1368 ff->param.dec_fmt.id = new_fmt_id;
1369 ff->param.dec_fmt.det.vid.size.w = ff->dec_ctx->coded_width;
1370 ff->param.dec_fmt.det.vid.size.h = ff->dec_ctx->coded_height;
1371
1372 /* Re-init format info and apply-param of decoder */
1373 ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param.dec_fmt.id);
1374 if (!ff->dec_vfi)
1375 return PJ_EUNKNOWN;
1376 pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
1377 ff->dec_vafp.size = ff->param.dec_fmt.det.vid.size;
1378 ff->dec_vafp.buffer = NULL;
1379 status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
1380 if (status != PJ_SUCCESS)
1381 return status;
1382
1383 /* Notify application via the bit_info field of pjmedia_frame */
1384 output->bit_info = PJMEDIA_VID_CODEC_EVENT_FMT_CHANGED;
1385 }
1386
1387 /* Check provided buffer size after format changed */
Nanang Izzuddin235e1b42011-02-28 18:59:47 +00001388 //if (vafp->framebytes > output_buf_len)
1389 //return PJ_ETOOSMALL;
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001390
1391 /* Get the decoded data */
1392 for (i = 0; i < ff->dec_vfi->plane_cnt; ++i) {
1393 pj_uint8_t *p = avframe.data[i];
1394
1395 /* The decoded data may contain padding */
1396 if (avframe.linesize[i]!=vafp->strides[i]) {
1397 /* Padding exists, copy line by line */
1398 pj_uint8_t *q_end;
1399
1400 q_end = q+vafp->plane_bytes[i];
1401 while(q < q_end) {
1402 pj_memcpy(q, p, vafp->strides[i]);
1403 q += vafp->strides[i];
1404 p += avframe.linesize[i];
1405 }
1406 } else {
1407 /* No padding, copy the whole plane */
1408 pj_memcpy(q, p, vafp->plane_bytes[i]);
1409 q += vafp->plane_bytes[i];
1410 }
1411 }
1412
Benny Prijonoc45d9512010-12-10 11:04:30 +00001413 output->size = vafp->framebytes;
1414 } else {
1415 return PJ_EUNKNOWN;
1416 }
1417
1418 return PJ_SUCCESS;
1419}
1420
1421/*
1422 * Recover lost frame.
1423 */
1424static pj_status_t ffmpeg_codec_recover( pjmedia_vid_codec *codec,
1425 unsigned output_buf_len,
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001426 pjmedia_frame *output)
Benny Prijonoc45d9512010-12-10 11:04:30 +00001427{
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001428 PJ_UNUSED_ARG(codec);
Benny Prijonoc45d9512010-12-10 11:04:30 +00001429 PJ_UNUSED_ARG(output_buf_len);
1430 PJ_UNUSED_ARG(output);
Benny Prijonoc45d9512010-12-10 11:04:30 +00001431
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001432 return PJ_ENOTSUP;
Benny Prijonoc45d9512010-12-10 11:04:30 +00001433}
1434
1435#ifdef _MSC_VER
1436# pragma comment( lib, "avcodec.lib")
Nanang Izzuddina9c1cf42011-02-24 07:47:55 +00001437# pragma comment( lib, "swscale.lib")
Benny Prijonoc45d9512010-12-10 11:04:30 +00001438#endif
1439
1440#endif /* PJMEDIA_HAS_FFMPEG_CODEC */
1441