diff options
author | Benny Prijono <bennylp@teluu.com> | 2011-09-29 08:31:15 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2011-09-29 08:31:15 +0000 |
commit | 21bee233619f1e2187345efd4eaed85e49facc5b (patch) | |
tree | 53db607a42e99c01d67c8e0612b29ec9313b4755 /pjmedia/src/pjmedia-codec/ffmpeg_codecs.c | |
parent | 90bbdfb85e44e2be7a185a7f8288bd50371d735a (diff) |
Closed #1361: codec API change. Details:
- changed encode(), packetize(), unpacketize(), and decode() to encode_begin(), encode_more(), and decode()
- codec has new "packing" setting
- updated stream, aviplay, codec-test, and stream-util due to above
- minor doxygen documentation fixes here and there
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@3776 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia/src/pjmedia-codec/ffmpeg_codecs.c')
-rw-r--r-- | pjmedia/src/pjmedia-codec/ffmpeg_codecs.c | 248 |
1 files changed, 208 insertions, 40 deletions
diff --git a/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c b/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c index 16afce33..94610068 100644 --- a/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c +++ b/pjmedia/src/pjmedia-codec/ffmpeg_codecs.c @@ -70,26 +70,20 @@ static pj_status_t ffmpeg_codec_modify(pjmedia_vid_codec *codec, const pjmedia_vid_codec_param *attr ); static pj_status_t ffmpeg_codec_get_param(pjmedia_vid_codec *codec, pjmedia_vid_codec_param *param); -static pj_status_t ffmpeg_packetize ( pjmedia_vid_codec *codec, - pj_uint8_t *buf, - pj_size_t buf_len, - unsigned *pos, - const pj_uint8_t **payload, - pj_size_t *payload_len); -static pj_status_t ffmpeg_unpacketize(pjmedia_vid_codec *codec, - const pj_uint8_t *payload, - pj_size_t payload_len, - pj_uint8_t *buf, - pj_size_t buf_len, - unsigned *pos); -static pj_status_t ffmpeg_codec_encode( pjmedia_vid_codec *codec, - const pjmedia_frame *input, - unsigned output_buf_len, - pjmedia_frame *output); -static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec, - const pjmedia_frame *input, - unsigned output_buf_len, - pjmedia_frame *output); +static pj_status_t ffmpeg_codec_encode_begin( pjmedia_vid_codec *codec, + const pjmedia_frame *input, + unsigned out_size, + pjmedia_frame *output, + pj_bool_t *has_more); +static pj_status_t ffmpeg_codec_encode_more(pjmedia_vid_codec *codec, + unsigned out_size, + pjmedia_frame *output, + pj_bool_t *has_more); +static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec, + pj_size_t pkt_count, + pjmedia_frame packets[], + unsigned out_size, + pjmedia_frame *output); /* Definition for FFMPEG codecs operations. */ static pjmedia_vid_codec_op ffmpeg_op = @@ -99,9 +93,8 @@ static pjmedia_vid_codec_op ffmpeg_op = &ffmpeg_codec_close, &ffmpeg_codec_modify, &ffmpeg_codec_get_param, - &ffmpeg_packetize, - &ffmpeg_unpacketize, - &ffmpeg_codec_encode, + &ffmpeg_codec_encode_begin, + &ffmpeg_codec_encode_more, &ffmpeg_codec_decode, NULL }; @@ -145,6 +138,15 @@ typedef struct ffmpeg_private const pjmedia_video_format_info *dec_vfi; pjmedia_video_apply_fmt_param dec_vafp; + /* Buffers, only needed for multi-packets */ + pj_bool_t whole; + void *enc_buf; + unsigned enc_buf_size; + unsigned enc_frame_len; + unsigned enc_processed; + void *dec_buf; + unsigned dec_buf_size; + /* The ffmpeg codec states. */ AVCodec *enc; AVCodec *dec; @@ -235,7 +237,7 @@ static FUNC_UNPACKETIZE(h263_unpacketize); /* Internal codec info */ -ffmpeg_codec_desc codec_desc[] = +static ffmpeg_codec_desc codec_desc[] = { #if ENABLE_H264 { @@ -477,7 +479,8 @@ static const ffmpeg_codec_desc* find_codec_desc_by_info( if (desc->enabled && (desc->info.fmt_id == info->fmt_id) && ((desc->info.dir & info->dir) == info->dir) && - (desc->info.pt == info->pt)) + (desc->info.pt == info->pt) && + (desc->info.packings & info->packings)) { return desc; } @@ -539,8 +542,7 @@ PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_init(pjmedia_vid_codec_mgr *mgr, av_log_set_level(AV_LOG_ERROR); /* Enum FFMPEG codecs */ - for (c=av_codec_next(NULL); c; c=av_codec_next(c)) - { + for (c=av_codec_next(NULL); c; c=av_codec_next(c)) { ffmpeg_codec_desc *desc; pjmedia_format_id fmt_id; int codec_info_idx; @@ -658,9 +660,11 @@ PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_init(pjmedia_vid_codec_mgr *mgr, if (desc->info.clock_rate == 0) desc->info.clock_rate = 90000; - /* Set RTP packetization support flag in the codec info */ - desc->info.has_rtp_pack = (desc->packetize != NULL) && - (desc->unpacketize != NULL); + /* Set supported packings */ + desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE; + if (desc->packetize && desc->unpacketize) + desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS; + } /* Review all codecs for applying base format, registering format match for @@ -706,8 +710,11 @@ PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_init(pjmedia_vid_codec_mgr *mgr, desc->info.dir |= copied_dir; desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE); - desc->info.has_rtp_pack = (desc->packetize != NULL) && - (desc->unpacketize != NULL); + + /* Set supported packings */ + desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE; + if (desc->packetize && desc->unpacketize) + desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS; if (copied_dir != PJMEDIA_DIR_NONE) { const char *dir_name[] = {NULL, "encoder", "decoder", "codec"}; @@ -801,6 +808,7 @@ static pj_status_t ffmpeg_default_attr( pjmedia_vid_codec_factory *factory, pjmedia_vid_codec_param *attr ) { const ffmpeg_codec_desc *desc; + unsigned i; PJ_ASSERT_RETURN(factory==&ffmpeg_factory.base, PJ_EINVAL); PJ_ASSERT_RETURN(info && attr, PJ_EINVAL); @@ -812,6 +820,20 @@ static pj_status_t ffmpeg_default_attr( pjmedia_vid_codec_factory *factory, pj_bzero(attr, sizeof(pjmedia_vid_codec_param)); + /* Scan the requested packings and use the lowest number */ + attr->packing = 0; + for (i=0; i<15; ++i) { + unsigned packing = (1 << i); + if ((desc->info.packings & info->packings) & packing) { + attr->packing = (pjmedia_vid_packing)packing; + break; + } + } + if (attr->packing == 0) { + /* No supported packing in info */ + return PJMEDIA_CODEC_EUNSUP; + } + /* Direction */ attr->dir = desc->info.dir; @@ -1152,6 +1174,16 @@ static pj_status_t ffmpeg_codec_open( pjmedia_vid_codec *codec, goto on_error; } + /* Alloc buffers if needed */ + ff->whole = (ff->param.packing == PJMEDIA_VID_PACKING_WHOLE); + if (!ff->whole) { + ff->enc_buf_size = ff->enc_vafp.framebytes; + ff->enc_buf = pj_pool_alloc(ff->pool, ff->enc_buf_size); + + ff->dec_buf_size = ff->dec_vafp.framebytes; + ff->dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size); + } + /* Update codec attributes, e.g: encoding format may be changed by * SDP fmtp negotiation. */ @@ -1259,10 +1291,10 @@ static pj_status_t ffmpeg_unpacketize(pjmedia_vid_codec *codec, /* * Encode frames. */ -static pj_status_t ffmpeg_codec_encode( pjmedia_vid_codec *codec, - const pjmedia_frame *input, - unsigned output_buf_len, - pjmedia_frame *output) +static pj_status_t ffmpeg_codec_encode_whole(pjmedia_vid_codec *codec, + const pjmedia_frame *input, + unsigned output_buf_len, + pjmedia_frame *output) { ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data; pj_uint8_t *p = (pj_uint8_t*)input->buf; @@ -1311,13 +1343,96 @@ static pj_status_t ffmpeg_codec_encode( pjmedia_vid_codec *codec, return PJ_SUCCESS; } +static pj_status_t ffmpeg_codec_encode_begin( pjmedia_vid_codec *codec, + const pjmedia_frame *input, + unsigned out_size, + pjmedia_frame *output, + pj_bool_t *has_more) +{ + ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data; + pj_status_t status; + + *has_more = PJ_FALSE; + + if (ff->whole) { + status = ffmpeg_codec_encode_whole(codec, input, out_size, output); + } else { + pjmedia_frame whole_frm; + const pj_uint8_t *payload; + pj_size_t payload_len; + + pj_bzero(&whole_frm, sizeof(whole_frm)); + whole_frm.buf = ff->enc_buf; + whole_frm.size = ff->enc_buf_size; + status = ffmpeg_codec_encode_whole(codec, input, + whole_frm.size, &whole_frm); + if (status != PJ_SUCCESS) + return status; + + ff->enc_frame_len = (unsigned)whole_frm.size; + ff->enc_processed = 0; + status = ffmpeg_packetize(codec, (pj_uint8_t*)whole_frm.buf, + whole_frm.size, &ff->enc_processed, + &payload, &payload_len); + if (status != PJ_SUCCESS) + return status; + + if (out_size < payload_len) + return PJMEDIA_CODEC_EFRMTOOSHORT; + + output->type = PJMEDIA_FRAME_TYPE_VIDEO; + pj_memcpy(output->buf, payload, payload_len); + output->size = payload_len; + + *has_more = (ff->enc_processed < ff->enc_frame_len); + } + + return status; +} + +static pj_status_t ffmpeg_codec_encode_more(pjmedia_vid_codec *codec, + unsigned out_size, + pjmedia_frame *output, + pj_bool_t *has_more) +{ + ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data; + const pj_uint8_t *payload; + pj_size_t payload_len; + pj_status_t status; + + *has_more = PJ_FALSE; + + if (ff->enc_processed >= ff->enc_frame_len) { + /* No more frame */ + return PJ_EEOF; + } + + status = ffmpeg_packetize(codec, (pj_uint8_t*)ff->enc_buf, + ff->enc_frame_len, &ff->enc_processed, + &payload, &payload_len); + if (status != PJ_SUCCESS) + return status; + + if (out_size < payload_len) + return PJMEDIA_CODEC_EFRMTOOSHORT; + + output->type = PJMEDIA_FRAME_TYPE_VIDEO; + pj_memcpy(output->buf, payload, payload_len); + output->size = payload_len; + + *has_more = (ff->enc_processed < ff->enc_frame_len); + + return PJ_SUCCESS; +} + + /* * Decode frame. */ -static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec, - const pjmedia_frame *input, - unsigned output_buf_len, - pjmedia_frame *output) +static pj_status_t ffmpeg_codec_decode_whole(pjmedia_vid_codec *codec, + const pjmedia_frame *input, + unsigned output_buf_len, + pjmedia_frame *output) { ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data; AVFrame avframe; @@ -1416,6 +1531,15 @@ static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec, if (status != PJ_SUCCESS) return status; + /* Realloc buffer if necessary */ + if (ff->dec_vafp.framebytes > ff->dec_buf_size) { + PJ_LOG(5,(THIS_FILE, "Reallocating decoding buffer %u --> %u", + (unsigned)ff->dec_buf_size, + (unsigned)ff->dec_vafp.framebytes)); + ff->dec_buf_size = ff->dec_vafp.framebytes; + ff->dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size); + } + /* Broadcast event */ if (pjmedia_event_publisher_has_sub(&codec->epub)) { pjmedia_event event; @@ -1475,6 +1599,50 @@ static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec, return PJ_SUCCESS; } +static pj_status_t ffmpeg_codec_decode( pjmedia_vid_codec *codec, + pj_size_t pkt_count, + pjmedia_frame packets[], + unsigned out_size, + pjmedia_frame *output) +{ + ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data; + pj_status_t status; + + PJ_ASSERT_RETURN(codec && pkt_count > 0 && packets && output, + PJ_EINVAL); + + if (ff->whole) { + pj_assert(pkt_count==1); + return ffmpeg_codec_decode_whole(codec, &packets[0], out_size, output); + } else { + pjmedia_frame whole_frm; + unsigned whole_len = 0; + unsigned i; + + for (i=0; i<pkt_count; ++i) { + if (whole_len + packets[i].size > ff->dec_buf_size) { + PJ_LOG(5,(THIS_FILE, "Decoding buffer overflow")); + break; + } + + status = ffmpeg_unpacketize(codec, packets[i].buf, packets[i].size, + ff->dec_buf, ff->dec_buf_size, + &whole_len); + if (status != PJ_SUCCESS) { + PJ_PERROR(5,(THIS_FILE, status, "Unpacketize error")); + continue; + } + } + + whole_frm.buf = ff->dec_buf; + whole_frm.size = whole_len; + whole_frm.timestamp = output->timestamp = packets[i].timestamp; + whole_frm.bit_info = 0; + + return ffmpeg_codec_decode_whole(codec, &whole_frm, out_size, output); + } +} + #ifdef _MSC_VER # pragma comment( lib, "avcodec.lib") |