12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066 |
- /*
- * Copyright (C) 2010-2011 Teluu Inc. (http://www.teluu.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <pjmedia-codec/ffmpeg_vid_codecs.h>
- #include <pjmedia-codec/h263_packetizer.h>
- #include <pjmedia-codec/h264_packetizer.h>
- #include <pjmedia-codec/vpx_packetizer.h>
- #include <pjmedia/errno.h>
- #include <pjmedia/vid_codec_util.h>
- #include <pj/assert.h>
- #include <pj/list.h>
- #include <pj/log.h>
- #include <pj/math.h>
- #include <pj/pool.h>
- #include <pj/string.h>
- #include <pj/os.h>
- /*
- * Only build this file if PJMEDIA_HAS_FFMPEG_VID_CODEC != 0 and
- * PJMEDIA_HAS_VIDEO != 0
- */
- #if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && \
- PJMEDIA_HAS_FFMPEG_VID_CODEC != 0 && \
- defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
- #define THIS_FILE "ffmpeg_vid_codecs.c"
- #include "../pjmedia/ffmpeg_util.h"
- #include <libavcodec/avcodec.h>
- #include <libavformat/avformat.h>
- #if LIBAVCODEC_VER_AT_LEAST(53,20)
- /* Needed by 264 so far, on libavcodec 53.20 */
- # include <libavutil/opt.h>
- #endif
- /* Various compatibility */
- #if LIBAVCODEC_VER_AT_LEAST(53,20)
- # define AVCODEC_OPEN(ctx,c) avcodec_open2(ctx,c,NULL)
- #else
- # define AVCODEC_OPEN(ctx,c) avcodec_open(ctx,c)
- #endif
- #if LIBAVCODEC_VER_AT_LEAST(53,61)
- # if LIBAVCODEC_VER_AT_LEAST(54,59)
- /* Not sure when AVCodec::encode is obsoleted/removed. */
- # define AVCODEC_HAS_ENCODE(c) (c->encode2 != (void*)0)
- # else
- /* Not sure when AVCodec::encode2 is introduced. It appears in
- * libavcodec 53.61 where some codecs actually still use AVCodec::encode
- * (e.g: H263, H264).
- */
- # define AVCODEC_HAS_ENCODE(c) (c->encode != (void*)0 || \
- c->encode2 != (void*)0)
- # endif
- # define AV_OPT_SET(obj,name,val,opt) (av_opt_set(obj,name,val,opt)==0)
- # define AV_OPT_SET_INT(obj,name,val) (av_opt_set_int(obj,name,val,0)==0)
- #else
- # define AVCODEC_HAS_ENCODE(c) (c->encode != (void*)0)
- # define AV_OPT_SET(obj,name,val,opt) (av_set_string3(obj,name,val,opt,NULL)==0)
- # define AV_OPT_SET_INT(obj,name,val) (av_set_int(obj,name,val)!=NULL)
- #endif
- #define AVCODEC_HAS_DECODE(c) (c->decode != (void*)0)
- /* AVCodec H264 default PT */
- #define AVC_H264_PT PJMEDIA_RTP_PT_H264_RSV3
- /* Prototypes for FFMPEG codecs factory */
- static pj_status_t ffmpeg_test_alloc( pjmedia_vid_codec_factory *factory,
- const pjmedia_vid_codec_info *id );
- static pj_status_t ffmpeg_default_attr( pjmedia_vid_codec_factory *factory,
- const pjmedia_vid_codec_info *info,
- pjmedia_vid_codec_param *attr );
- static pj_status_t ffmpeg_enum_codecs( pjmedia_vid_codec_factory *factory,
- unsigned *count,
- pjmedia_vid_codec_info codecs[]);
- static pj_status_t ffmpeg_alloc_codec( pjmedia_vid_codec_factory *factory,
- const pjmedia_vid_codec_info *info,
- pjmedia_vid_codec **p_codec);
- static pj_status_t ffmpeg_dealloc_codec( pjmedia_vid_codec_factory *factory,
- pjmedia_vid_codec *codec );
- /* Prototypes for FFMPEG codecs implementation. */
- static pj_status_t ffmpeg_codec_init( pjmedia_vid_codec *codec,
- pj_pool_t *pool );
- static pj_status_t ffmpeg_codec_open( pjmedia_vid_codec *codec,
- pjmedia_vid_codec_param *attr );
- static pj_status_t ffmpeg_codec_close( pjmedia_vid_codec *codec );
- 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_codec_encode_begin(pjmedia_vid_codec *codec,
- const pjmedia_vid_encode_opt *opt,
- 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 =
- {
- &ffmpeg_codec_init,
- &ffmpeg_codec_open,
- &ffmpeg_codec_close,
- &ffmpeg_codec_modify,
- &ffmpeg_codec_get_param,
- &ffmpeg_codec_encode_begin,
- &ffmpeg_codec_encode_more,
- &ffmpeg_codec_decode,
- NULL
- };
- /* Definition for FFMPEG codecs factory operations. */
- static pjmedia_vid_codec_factory_op ffmpeg_factory_op =
- {
- &ffmpeg_test_alloc,
- &ffmpeg_default_attr,
- &ffmpeg_enum_codecs,
- &ffmpeg_alloc_codec,
- &ffmpeg_dealloc_codec
- };
- /* FFMPEG codecs factory */
- static struct ffmpeg_factory {
- pjmedia_vid_codec_factory base;
- pjmedia_vid_codec_mgr *mgr;
- pj_pool_factory *pf;
- pj_pool_t *pool;
- pj_mutex_t *mutex;
- } ffmpeg_factory;
- typedef struct ffmpeg_codec_desc ffmpeg_codec_desc;
- /* FFMPEG codecs private data. */
- typedef struct ffmpeg_private
- {
- const ffmpeg_codec_desc *desc;
- pjmedia_vid_codec_param *param; /**< Codec param */
- pj_pool_t *pool; /**< Pool for each instance */
- /* Format info and apply format param */
- const pjmedia_video_format_info *enc_vfi;
- pjmedia_video_apply_fmt_param enc_vafp;
- 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;
- pj_bool_t enc_buf_is_keyframe;
- unsigned enc_frame_len;
- unsigned enc_processed;
- void *dec_buf;
- unsigned dec_buf_size;
- pj_timestamp last_dec_keyframe_ts;
- /* The ffmpeg codec states. */
- const AVCodec *enc;
- const AVCodec *dec;
- AVCodecContext *enc_ctx;
- AVCodecContext *dec_ctx;
- /* The ffmpeg decoder cannot set the output format, so format conversion
- * may be needed for post-decoding.
- */
- enum AVPixelFormat expected_dec_fmt;
- /**< Expected output format of
- ffmpeg decoder */
- void *data; /**< Codec specific data */
- } ffmpeg_private;
- /* Shortcuts for packetize & unpacketize function declaration,
- * as it has long params and is reused many times!
- */
- #define FUNC_PACKETIZE(name) \
- pj_status_t(name)(ffmpeg_private *ff, pj_uint8_t *bits, \
- pj_size_t bits_len, unsigned *bits_pos, \
- pj_uint8_t *payload, pj_size_t *payload_len, \
- pj_bool_t is_keyframe)
- #define FUNC_UNPACKETIZE(name) \
- pj_status_t(name)(ffmpeg_private *ff, const pj_uint8_t *payload, \
- pj_size_t payload_len, pj_uint8_t *bits, \
- pj_size_t bits_len, unsigned *bits_pos)
- #define FUNC_FMT_MATCH(name) \
- pj_status_t(name)(pj_pool_t *pool, \
- pjmedia_sdp_media *offer, unsigned o_fmt_idx, \
- pjmedia_sdp_media *answer, unsigned a_fmt_idx, \
- unsigned option)
- /* Type definition of codec specific functions */
- typedef FUNC_PACKETIZE(*func_packetize);
- typedef FUNC_UNPACKETIZE(*func_unpacketize);
- typedef pj_status_t (*func_preopen) (ffmpeg_private *ff);
- typedef pj_status_t (*func_postopen) (ffmpeg_private *ff);
- typedef FUNC_FMT_MATCH(*func_sdp_fmt_match);
- /* FFMPEG codec info */
- struct ffmpeg_codec_desc
- {
- /* Predefined info */
- pjmedia_vid_codec_info info;
- pjmedia_format_id base_fmt_id; /**< Some codecs may be exactly
- same or compatible with
- another codec, base format
- will tell the initializer
- to copy this codec desc
- from its base format */
- pjmedia_rect_size size;
- pjmedia_ratio fps;
- pj_uint32_t avg_bps;
- pj_uint32_t max_bps;
- func_packetize packetize;
- func_unpacketize unpacketize;
- func_preopen preopen;
- func_preopen postopen;
- func_sdp_fmt_match sdp_fmt_match;
- pjmedia_codec_fmtp dec_fmtp;
- /* Init time defined info */
- pj_bool_t enabled;
- const AVCodec *enc;
- const AVCodec *dec;
- };
- #if PJMEDIA_HAS_FFMPEG_CODEC_H264 && !LIBAVCODEC_VER_AT_LEAST(53,20)
- # error "Must use libavcodec version 53.20 or later to enable FFMPEG H264"
- #endif
- /* H264 constants */
- #define PROFILE_H264_BASELINE 66
- #define PROFILE_H264_MAIN 77
- /* Codec specific functions */
- #if PJMEDIA_HAS_FFMPEG_CODEC_VP8 || PJMEDIA_HAS_FFMPEG_CODEC_VP9
- static pj_status_t vpx_preopen(ffmpeg_private *ff);
- static pj_status_t vpx_postopen(ffmpeg_private *ff);
- static FUNC_PACKETIZE(vpx_packetize);
- static FUNC_UNPACKETIZE(vpx_unpacketize);
- #endif
- #if PJMEDIA_HAS_FFMPEG_CODEC_H264
- static pj_status_t h264_preopen(ffmpeg_private *ff);
- static pj_status_t h264_postopen(ffmpeg_private *ff);
- static FUNC_PACKETIZE(h264_packetize);
- static FUNC_UNPACKETIZE(h264_unpacketize);
- #endif
- static pj_status_t h263_preopen(ffmpeg_private *ff);
- static FUNC_PACKETIZE(h263_packetize);
- static FUNC_UNPACKETIZE(h263_unpacketize);
- /* Internal codec info */
- static ffmpeg_codec_desc codec_desc[] =
- {
- #if PJMEDIA_HAS_FFMPEG_CODEC_H264
- {
- {PJMEDIA_FORMAT_H264, AVC_H264_PT, {"H264",4},
- {"Constrained Baseline (level=30, pack=1)", 39}},
- 0,
- {720, 480}, {15, 1}, 256000, 256000,
- &h264_packetize, &h264_unpacketize, &h264_preopen, &h264_postopen,
- &pjmedia_vid_codec_h264_match_sdp,
- /* Leading space for better compatibility (strange indeed!) */
- {2, { {{"profile-level-id",16}, {"42e01e",6}},
- {{" packetization-mode",19}, {"1",1}}, } },
- },
- #endif
- #if PJMEDIA_HAS_FFMPEG_CODEC_VP8
- {
- {PJMEDIA_FORMAT_VP8, PJMEDIA_RTP_PT_VP8_RSV2, {"VP8",3},
- {"FF VP8", 6}},
- 0,
- {720, 480}, {15, 1}, 256000, 256000,
- &vpx_packetize, &vpx_unpacketize, &vpx_preopen, &vpx_postopen, NULL,
- {2, { {{"max-fr",6}, {"30",2}},
- {{" max-fs",7}, {"580",3}}, } },
- },
- #endif
- #if PJMEDIA_HAS_FFMPEG_CODEC_VP9
- {
- {PJMEDIA_FORMAT_VP9, PJMEDIA_RTP_PT_VP9_RSV2, {"VP9",3},
- {"FF VP9", 6}},
- 0,
- {720, 480}, {15, 1}, 256000, 256000,
- &vpx_packetize, &vpx_unpacketize, &vpx_preopen, &vpx_postopen, NULL,
- {2, { {{"max-fr",6}, {"30",2}},
- {{" max-fs",7}, {"580",3}}, } },
- },
- #endif
- #if PJMEDIA_HAS_FFMPEG_CODEC_H263P
- {
- {PJMEDIA_FORMAT_H263P, PJMEDIA_RTP_PT_H263P, {"H263-1998",9}},
- PJMEDIA_FORMAT_H263,
- {352, 288}, {15, 1}, 256000, 256000,
- &h263_packetize, &h263_unpacketize, &h263_preopen, NULL, NULL,
- {2, { {{"CIF",3}, {"1",1}},
- {{"QCIF",4}, {"1",1}}, } },
- },
- #endif
- {
- {PJMEDIA_FORMAT_H263, PJMEDIA_RTP_PT_H263, {"H263",4}},
- },
- {
- {PJMEDIA_FORMAT_H261, PJMEDIA_RTP_PT_H261, {"H261",4}},
- },
- {
- {PJMEDIA_FORMAT_MJPEG, PJMEDIA_RTP_PT_JPEG, {"JPEG",4}},
- PJMEDIA_FORMAT_MJPEG, {640, 480}, {25, 1},
- },
- {
- {PJMEDIA_FORMAT_MPEG4, 0, {"MP4V",4}},
- PJMEDIA_FORMAT_MPEG4, {640, 480}, {25, 1},
- },
- };
- #if PJMEDIA_HAS_FFMPEG_CODEC_VP8 || PJMEDIA_HAS_FFMPEG_CODEC_VP9
- typedef struct vpx_data
- {
- pjmedia_vpx_packetizer *pktz;
- } vpx_data;
- static pj_status_t vpx_preopen(ffmpeg_private *ff)
- {
- vpx_data *data;
- pjmedia_vpx_packetizer_cfg pktz_cfg;
- pj_status_t status;
- data = PJ_POOL_ZALLOC_T(ff->pool, vpx_data);
- ff->data = data;
- /* Parse local fmtp */
- if (!ff->param->ignore_fmtp)
- {
- pjmedia_vid_codec_vpx_fmtp vpx_fmtp;
- const unsigned MAX_RX_RES = 1200;
- unsigned max_res = MAX_RX_RES;
- status = pjmedia_vid_codec_vpx_parse_fmtp(&ff->param->dec_fmtp, &vpx_fmtp);
- if (status != PJ_SUCCESS)
- {
- PJ_LOG(2, (THIS_FILE, "Parse vpx fmtp fail, status:%d", status));
- return status;
- }
- if (vpx_fmtp.max_fs > 0)
- {
- max_res = ((int)pj_isqrt(vpx_fmtp.max_fs * 8)) * 16;
- }
- ff->dec_buf_size = (max_res * max_res * 3 >> 1) + (max_res);
- }
- /* Create packetizer */
- pktz_cfg.fmt_id = ff->desc->info.fmt_id;
- pktz_cfg.mtu = ff->param->enc_mtu;
- status = pjmedia_vpx_packetizer_create(ff->pool, &pktz_cfg, &data->pktz);
- if (status != PJ_SUCCESS)
- {
- return status;
- }
- return PJ_SUCCESS;
- }
- static pj_status_t vpx_postopen(ffmpeg_private *ff)
- {
- vpx_data *data = (vpx_data *)ff->data;
- PJ_UNUSED_ARG(data);
- return PJ_SUCCESS;
- }
- static FUNC_PACKETIZE(vpx_packetize)
- {
- vpx_data *data = (vpx_data *)ff->data;
- pj_status_t status;
- unsigned payload_desc_size = 1;
- pj_uint8_t *outbuf = payload;
- pj_size_t out_size = *payload_len;
- out_size -= payload_desc_size;
- status = pjmedia_vpx_packetize(data->pktz, bits_len, bits_pos, is_keyframe,
- &outbuf, &out_size);
- if (status != PJ_SUCCESS)
- return status;
- pj_memcpy(outbuf + payload_desc_size, bits + *bits_pos, out_size);
- *payload_len = out_size + payload_desc_size;
- *bits_pos += out_size;
- return PJ_SUCCESS;
- }
- static FUNC_UNPACKETIZE(vpx_unpacketize)
- {
- vpx_data *data = (vpx_data *)ff->data;
- unsigned desc_len = 0;
- pj_status_t status;
- unsigned pos = *bits_pos;
- status = pjmedia_vpx_unpacketize(data->pktz, payload, payload_len, &desc_len);
- if (status != PJ_SUCCESS)
- return status;
- payload_len -= desc_len;
- if (pos + payload_len > bits_len)
- {
- PJ_LOG(2, (THIS_FILE, "Vpx unpacketize buffer overflow"));
- return PJMEDIA_CODEC_EFRMTOOSHORT;
- }
- pj_memcpy(bits + pos, (char *)payload + desc_len, payload_len);
- pos += payload_len;
- *bits_pos = pos;
- return PJ_SUCCESS;
- }
- #endif // PJMEDIA_HAS_FFMPEG_CODEC_VP8/VP9
- #if PJMEDIA_HAS_FFMPEG_CODEC_H264
- typedef struct h264_data
- {
- pjmedia_vid_codec_h264_fmtp fmtp;
- pjmedia_h264_packetizer *pktz;
- } h264_data;
- static pj_status_t h264_preopen(ffmpeg_private *ff)
- {
- h264_data *data;
- pjmedia_h264_packetizer_cfg pktz_cfg;
- pj_status_t status;
- data = PJ_POOL_ZALLOC_T(ff->pool, h264_data);
- ff->data = data;
- /* Parse remote fmtp */
- status = pjmedia_vid_codec_h264_parse_fmtp(&ff->param->enc_fmtp,
- &data->fmtp);
- if (status != PJ_SUCCESS)
- return status;
- /* Create packetizer */
- pktz_cfg.mtu = ff->param->enc_mtu;
- pktz_cfg.unpack_nal_start = 0;
- #if 0
- if (data->fmtp.packetization_mode == 0)
- pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL;
- else if (data->fmtp.packetization_mode == 1)
- pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED;
- else
- return PJ_ENOTSUP;
- #else
- if (data->fmtp.packetization_mode!=
- PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL &&
- data->fmtp.packetization_mode!=
- PJMEDIA_H264_PACKETIZER_MODE_NON_INTERLEAVED)
- {
- return PJ_ENOTSUP;
- }
- /* Better always send in single NAL mode for better compatibility */
- pktz_cfg.mode = PJMEDIA_H264_PACKETIZER_MODE_SINGLE_NAL;
- #endif
- status = pjmedia_h264_packetizer_create(ff->pool, &pktz_cfg, &data->pktz);
- if (status != PJ_SUCCESS)
- return status;
- /* Apply SDP fmtp to format in codec param */
- if (!ff->param->ignore_fmtp) {
- status = pjmedia_vid_codec_h264_apply_fmtp(ff->param);
- if (status != PJ_SUCCESS)
- return status;
- }
- if (ff->param->dir & PJMEDIA_DIR_ENCODING) {
- pjmedia_video_format_detail *vfd;
- AVCodecContext *ctx = ff->enc_ctx;
- const char *profile = NULL;
- vfd = pjmedia_format_get_video_format_detail(&ff->param->enc_fmt,
- PJ_TRUE);
- /* Override generic params after applying SDP fmtp */
- ctx->width = vfd->size.w;
- ctx->height = vfd->size.h;
- ctx->time_base.num = vfd->fps.denum;
- ctx->time_base.den = vfd->fps.num;
- /* Apply profile. */
- ctx->profile = data->fmtp.profile_idc;
- switch (ctx->profile) {
- case PROFILE_H264_BASELINE:
- profile = "baseline";
- break;
- case PROFILE_H264_MAIN:
- profile = "main";
- break;
- default:
- break;
- }
- if (profile && !AV_OPT_SET(ctx->priv_data, "profile", profile, 0))
- {
- PJ_LOG(3, (THIS_FILE, "Failed to set H264 profile to '%s'",
- profile));
- }
- /* Apply profile constraint bits. */
- //PJ_TODO(set_h264_constraint_bits_properly_in_ffmpeg);
- if (data->fmtp.profile_iop) {
- #if defined(FF_PROFILE_H264_CONSTRAINED)
- ctx->profile |= FF_PROFILE_H264_CONSTRAINED;
- #endif
- }
- /* Apply profile level. */
- ctx->level = data->fmtp.level;
- /* Limit NAL unit size as we prefer single NAL unit packetization */
- if (!AV_OPT_SET_INT(ctx->priv_data, "slice-max-size", ff->param->enc_mtu))
- {
- PJ_LOG(3, (THIS_FILE, "Failed to set H264 max NAL size to %d",
- ff->param->enc_mtu));
- }
- /* Apply intra-refresh */
- if (!AV_OPT_SET_INT(ctx->priv_data, "intra-refresh", 1))
- {
- PJ_LOG(3, (THIS_FILE, "Failed to set x264 intra-refresh"));
- }
- /* Misc x264 settings (performance, quality, latency, etc).
- * Let's just use the x264 predefined preset & tune.
- */
- if (!AV_OPT_SET(ctx->priv_data, "preset", "veryfast", 0)) {
- PJ_LOG(3, (THIS_FILE, "Failed to set x264 preset 'veryfast'"));
- }
- if (!AV_OPT_SET(ctx->priv_data, "tune", "animation+zerolatency", 0)) {
- PJ_LOG(3, (THIS_FILE, "Failed to set x264 tune 'zerolatency'"));
- }
- }
- if (ff->param->dir & PJMEDIA_DIR_DECODING) {
- AVCodecContext *ctx = ff->dec_ctx;
- /* Apply the "sprop-parameter-sets" fmtp from remote SDP to
- * extradata of ffmpeg codec context.
- */
- if (data->fmtp.sprop_param_sets_len) {
- ctx->extradata_size = (int)data->fmtp.sprop_param_sets_len;
- ctx->extradata = data->fmtp.sprop_param_sets;
- }
- }
- return PJ_SUCCESS;
- }
- static pj_status_t h264_postopen(ffmpeg_private *ff)
- {
- h264_data *data = (h264_data*)ff->data;
- PJ_UNUSED_ARG(data);
- return PJ_SUCCESS;
- }
- static FUNC_PACKETIZE(h264_packetize)
- {
- PJ_UNUSED_ARG(is_keyframe);
- h264_data *data = (h264_data*)ff->data;
- pj_status_t status;
- pj_uint8_t *outbuf = payload;
- pj_size_t out_size = *payload_len;
- status = pjmedia_h264_packetize(data->pktz, bits, bits_len, bits_pos,
- (const pj_uint8_t **)&payload, payload_len);
- if (status != PJ_SUCCESS)
- return status;
- if (out_size < *payload_len)
- return PJMEDIA_CODEC_EFRMTOOSHORT;
- pj_memcpy(outbuf, payload, *payload_len);
- return PJ_SUCCESS;
- }
- static FUNC_UNPACKETIZE(h264_unpacketize)
- {
- h264_data *data = (h264_data*)ff->data;
- return pjmedia_h264_unpacketize(data->pktz, payload, payload_len,
- bits, bits_len, bits_pos);
- }
- #endif /* PJMEDIA_HAS_FFMPEG_CODEC_H264 */
- #if PJMEDIA_HAS_FFMPEG_CODEC_H263P
- typedef struct h263_data
- {
- pjmedia_h263_packetizer *pktz;
- } h263_data;
- /* H263 pre-open */
- static pj_status_t h263_preopen(ffmpeg_private *ff)
- {
- h263_data *data;
- pjmedia_h263_packetizer_cfg pktz_cfg;
- pj_status_t status;
- data = PJ_POOL_ZALLOC_T(ff->pool, h263_data);
- ff->data = data;
- /* Create packetizer */
- pktz_cfg.mtu = ff->param->enc_mtu;
- pktz_cfg.mode = PJMEDIA_H263_PACKETIZER_MODE_RFC4629;
- status = pjmedia_h263_packetizer_create(ff->pool, &pktz_cfg, &data->pktz);
- if (status != PJ_SUCCESS)
- return status;
- /* Apply fmtp settings to codec param */
- if (!ff->param->ignore_fmtp) {
- status = pjmedia_vid_codec_h263_apply_fmtp(ff->param);
- }
- /* Override generic params after applying SDP fmtp */
- if (ff->param->dir & PJMEDIA_DIR_ENCODING) {
- pjmedia_video_format_detail *vfd;
- AVCodecContext *ctx = ff->enc_ctx;
- vfd = pjmedia_format_get_video_format_detail(&ff->param->enc_fmt,
- PJ_TRUE);
- /* Override generic params after applying SDP fmtp */
- ctx->width = vfd->size.w;
- ctx->height = vfd->size.h;
- ctx->time_base.num = vfd->fps.denum;
- ctx->time_base.den = vfd->fps.num;
- }
- return status;
- }
- static FUNC_PACKETIZE(h263_packetize)
- {
- PJ_UNUSED_ARG(is_keyframe);
- h263_data *data = (h263_data*)ff->data;
- pj_status_t status;
- pj_uint8_t *outbuf = payload;
- pj_size_t out_size = *payload_len;
- status = pjmedia_h263_packetize(data->pktz, bits, bits_len, bits_pos,
- &payload, payload_len);
- if (status != PJ_SUCCESS)
- return status;
- if (out_size < *payload_len)
- return PJMEDIA_CODEC_EFRMTOOSHORT;
- pj_memcpy(outbuf, payload, *payload_len);
- return PJ_SUCCESS;
- }
- static FUNC_UNPACKETIZE(h263_unpacketize)
- {
- h263_data *data = (h263_data*)ff->data;
- return pjmedia_h263_unpacketize(data->pktz, payload, payload_len,
- bits, bits_len, bits_pos);
- }
- #endif /* PJMEDIA_HAS_FFMPEG_CODEC_H263P */
- static const ffmpeg_codec_desc* find_codec_desc_by_info(
- const pjmedia_vid_codec_info *info)
- {
- unsigned i;
- for (i=0; i<PJ_ARRAY_SIZE(codec_desc); ++i) {
- ffmpeg_codec_desc *desc = &codec_desc[i];
- if (desc->enabled &&
- (desc->info.fmt_id == info->fmt_id) &&
- ((desc->info.dir & info->dir) == info->dir) &&
- (desc->info.pt == info->pt) &&
- (desc->info.packings & info->packings))
- {
- return desc;
- }
- }
- return NULL;
- }
- static int find_codec_idx_by_fmt_id(pjmedia_format_id fmt_id)
- {
- unsigned i;
- for (i=0; i<PJ_ARRAY_SIZE(codec_desc); ++i) {
- if (codec_desc[i].info.fmt_id == fmt_id)
- return i;
- }
- return -1;
- }
- static void init_codec(AVCodec *c, pj_bool_t is_encoder,
- pj_bool_t is_decoder)
- {
- pj_status_t status;
- ffmpeg_codec_desc *desc;
- pjmedia_format_id fmt_id;
- int codec_info_idx;
- #if LIBAVCODEC_VERSION_MAJOR <= 52
- # define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
- #endif
- if (c->type != AVMEDIA_TYPE_VIDEO)
- return;
- /* Video encoder and decoder are usually implemented in separate
- * AVCodec instances. While the codec attributes (e.g: raw formats,
- * supported fps) are in the encoder.
- */
- status = CodecID_to_pjmedia_format_id(c->id, &fmt_id);
- /* Skip if format ID is unknown */
- if (status != PJ_SUCCESS)
- return;
- codec_info_idx = find_codec_idx_by_fmt_id(fmt_id);
- /* Skip if codec is unwanted by this wrapper (not listed in
- * the codec info array)
- */
- if (codec_info_idx < 0)
- return;
- desc = &codec_desc[codec_info_idx];
- /* Skip duplicated codec implementation */
- if ((is_encoder && (desc->info.dir & PJMEDIA_DIR_ENCODING))
- ||
- (is_decoder && (desc->info.dir & PJMEDIA_DIR_DECODING)))
- {
- return;
- }
- /* Get raw/decoded format ids in the encoder */
- if (c->pix_fmts && is_encoder) {
- pjmedia_format_id raw_fmt[PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT];
- unsigned raw_fmt_cnt = 0;
- unsigned raw_fmt_cnt_should_be = 0;
- const enum AVPixelFormat *p = c->pix_fmts;
- for(;(p && *p != -1) &&
- (raw_fmt_cnt < PJMEDIA_VID_CODEC_MAX_DEC_FMT_CNT);
- ++p)
- {
- pjmedia_format_id fmt_id;
- raw_fmt_cnt_should_be++;
- status = PixelFormat_to_pjmedia_format_id(*p, &fmt_id);
- if (status != PJ_SUCCESS) {
- PJ_PERROR(6, (THIS_FILE, status,
- "Unrecognized ffmpeg pixel format %d", *p));
- continue;
- }
- //raw_fmt[raw_fmt_cnt++] = fmt_id;
- /* Disable some formats due to H.264 error:
- * x264 [error]: baseline profile doesn't support 4:4:4
- */
- if (desc->info.pt != PJMEDIA_RTP_PT_H264 ||
- fmt_id != PJMEDIA_FORMAT_RGB24)
- {
- raw_fmt[raw_fmt_cnt++] = fmt_id;
- }
- }
- if (raw_fmt_cnt == 0) {
- PJ_LOG(5, (THIS_FILE, "No recognized raw format "
- "for codec [%s/%s], codec ignored",
- c->name, c->long_name));
- /* Skip this encoder */
- return;
- }
- if (raw_fmt_cnt < raw_fmt_cnt_should_be) {
- PJ_LOG(6, (THIS_FILE, "Codec [%s/%s] have %d raw formats, "
- "recognized only %d raw formats",
- c->name, c->long_name,
- raw_fmt_cnt_should_be, raw_fmt_cnt));
- }
- desc->info.dec_fmt_id_cnt = raw_fmt_cnt;
- pj_memcpy(desc->info.dec_fmt_id, raw_fmt,
- sizeof(raw_fmt[0])*raw_fmt_cnt);
- }
- /* Get supported framerates */
- if (c->supported_framerates) {
- const AVRational *fr = c->supported_framerates;
- while ((fr->num != 0 || fr->den != 0) &&
- desc->info.fps_cnt < PJMEDIA_VID_CODEC_MAX_FPS_CNT)
- {
- desc->info.fps[desc->info.fps_cnt].num = fr->num;
- desc->info.fps[desc->info.fps_cnt].denum = fr->den;
- ++desc->info.fps_cnt;
- ++fr;
- }
- }
- /* Get ffmpeg encoder instance */
- if (is_encoder && !desc->enc) {
- desc->info.dir |= PJMEDIA_DIR_ENCODING;
- desc->enc = c;
- }
- /* Get ffmpeg decoder instance */
- if (is_decoder && !desc->dec) {
- desc->info.dir |= PJMEDIA_DIR_DECODING;
- desc->dec = c;
- }
- /* Enable this codec when any ffmpeg codec instance are recognized
- * and the supported raw formats info has been collected.
- */
- if ((desc->dec || desc->enc) && desc->info.dec_fmt_id_cnt)
- {
- desc->enabled = PJ_TRUE;
- }
- /* Normalize default value of clock rate */
- if (desc->info.clock_rate == 0)
- desc->info.clock_rate = 90000;
- /* Set supported packings */
- desc->info.packings |= PJMEDIA_VID_PACKING_WHOLE;
- if (desc->packetize && desc->unpacketize)
- desc->info.packings |= PJMEDIA_VID_PACKING_PACKETS;
- }
- /*
- * Initialize and register FFMPEG codec factory to pjmedia endpoint.
- */
- PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_vid_init(pjmedia_vid_codec_mgr *mgr,
- pj_pool_factory *pf)
- {
- pj_pool_t *pool;
- AVCodec *c;
- pj_status_t status;
- unsigned i;
- if (ffmpeg_factory.pool != NULL) {
- /* Already initialized. */
- return PJ_SUCCESS;
- }
- if (!mgr) mgr = pjmedia_vid_codec_mgr_instance();
- PJ_ASSERT_RETURN(mgr, PJ_EINVAL);
- /* Create FFMPEG codec factory. */
- ffmpeg_factory.base.op = &ffmpeg_factory_op;
- ffmpeg_factory.base.factory_data = NULL;
- ffmpeg_factory.mgr = mgr;
- ffmpeg_factory.pf = pf;
- pool = pj_pool_create(pf, "ffmpeg codec factory", 256, 256, NULL);
- if (!pool)
- return PJ_ENOMEM;
- /* Create mutex. */
- status = pj_mutex_create_simple(pool, "ffmpeg codec factory",
- &ffmpeg_factory.mutex);
- if (status != PJ_SUCCESS)
- goto on_error;
- pjmedia_ffmpeg_add_ref();
- #if !LIBAVCODEC_VER_AT_LEAST(53,20)
- /* avcodec_init() dissappeared between version 53.20 and 54.15, not sure
- * exactly when
- */
- avcodec_init();
- #endif
- #if LIBAVCODEC_VER_AT_LEAST(58,137)
- for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
- unsigned codec_id;
- pjmedia_format_id_to_CodecID(codec_desc[i].info.fmt_id, &codec_id);
- c = avcodec_find_encoder(codec_id);
- if (c)
- init_codec(c, PJ_TRUE, PJ_FALSE);
- c = avcodec_find_decoder(codec_id);
- if (c)
- init_codec(c, PJ_FALSE, PJ_TRUE);
- }
- #else
- avcodec_register_all();
- /* Enum FFMPEG codecs */
- for (c=av_codec_next(NULL); c; c=av_codec_next(c)) {
- init_codec(c, AVCODEC_HAS_ENCODE(c), AVCODEC_HAS_DECODE(c));
- }
- #endif
- /* Review all codecs for applying base format, registering format match for
- * SDP negotiation, etc.
- */
- for (i = 0; i < PJ_ARRAY_SIZE(codec_desc); ++i) {
- ffmpeg_codec_desc *desc = &codec_desc[i];
- /* Init encoder/decoder description from base format */
- if (desc->base_fmt_id && (!desc->dec || !desc->enc)) {
- ffmpeg_codec_desc *base_desc = NULL;
- int base_desc_idx;
- pjmedia_dir copied_dir = PJMEDIA_DIR_NONE;
- base_desc_idx = find_codec_idx_by_fmt_id(desc->base_fmt_id);
- if (base_desc_idx != -1)
- base_desc = &codec_desc[base_desc_idx];
- if (!base_desc || !base_desc->enabled)
- continue;
- /* Copy description from base codec */
- if (!desc->info.dec_fmt_id_cnt) {
- desc->info.dec_fmt_id_cnt = base_desc->info.dec_fmt_id_cnt;
- pj_memcpy(desc->info.dec_fmt_id, base_desc->info.dec_fmt_id,
- sizeof(pjmedia_format_id)*desc->info.dec_fmt_id_cnt);
- }
- if (!desc->info.fps_cnt) {
- desc->info.fps_cnt = base_desc->info.fps_cnt;
- pj_memcpy(desc->info.fps, base_desc->info.fps,
- sizeof(desc->info.fps[0])*desc->info.fps_cnt);
- }
- if (!desc->info.clock_rate) {
- desc->info.clock_rate = base_desc->info.clock_rate;
- }
- if (!desc->dec && base_desc->dec) {
- copied_dir |= PJMEDIA_DIR_DECODING;
- desc->dec = base_desc->dec;
- }
- if (!desc->enc && base_desc->enc) {
- copied_dir |= PJMEDIA_DIR_ENCODING;
- desc->enc = base_desc->enc;
- }
- desc->info.dir |= copied_dir;
- desc->enabled = (desc->info.dir != PJMEDIA_DIR_NONE);
- /* 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"};
- PJ_LOG(5, (THIS_FILE, "The %.*s %s is using base codec (%.*s)",
- (int)desc->info.encoding_name.slen,
- desc->info.encoding_name.ptr,
- dir_name[copied_dir],
- (int)base_desc->info.encoding_name.slen,
- base_desc->info.encoding_name.ptr));
- }
- }
- /* Registering format match for SDP negotiation */
- if (desc->sdp_fmt_match) {
- status = pjmedia_sdp_neg_register_fmt_match_cb(
- &desc->info.encoding_name,
- desc->sdp_fmt_match);
- pj_assert(status == PJ_SUCCESS);
- }
- /* Print warning about missing encoder/decoder */
- if (!desc->enc) {
- PJ_LOG(4, (THIS_FILE, "Cannot find %.*s encoder in ffmpeg library",
- (int)desc->info.encoding_name.slen,
- desc->info.encoding_name.ptr));
- }
- if (!desc->dec) {
- PJ_LOG(4, (THIS_FILE, "Cannot find %.*s decoder in ffmpeg library",
- (int)desc->info.encoding_name.slen,
- desc->info.encoding_name.ptr));
- }
- }
- /* Register codec factory to codec manager. */
- status = pjmedia_vid_codec_mgr_register_factory(mgr,
- &ffmpeg_factory.base);
- if (status != PJ_SUCCESS)
- goto on_error;
- ffmpeg_factory.pool = pool;
- /* Done. */
- return PJ_SUCCESS;
- on_error:
- pj_pool_release(pool);
- return status;
- }
- /*
- * Unregister FFMPEG codecs factory from pjmedia endpoint.
- */
- PJ_DEF(pj_status_t) pjmedia_codec_ffmpeg_vid_deinit(void)
- {
- pj_status_t status = PJ_SUCCESS;
- if (ffmpeg_factory.pool == NULL) {
- /* Already deinitialized */
- return PJ_SUCCESS;
- }
- pj_mutex_lock(ffmpeg_factory.mutex);
- /* Unregister FFMPEG codecs factory. */
- status = pjmedia_vid_codec_mgr_unregister_factory(ffmpeg_factory.mgr,
- &ffmpeg_factory.base);
- /* Destroy mutex. */
- pj_mutex_unlock(ffmpeg_factory.mutex);
- pj_mutex_destroy(ffmpeg_factory.mutex);
- ffmpeg_factory.mutex = NULL;
- /* Destroy pool. */
- pj_pool_release(ffmpeg_factory.pool);
- ffmpeg_factory.pool = NULL;
- pjmedia_ffmpeg_dec_ref();
- return status;
- }
- /*
- * Check if factory can allocate the specified codec.
- */
- static pj_status_t ffmpeg_test_alloc( pjmedia_vid_codec_factory *factory,
- const pjmedia_vid_codec_info *info )
- {
- const ffmpeg_codec_desc *desc;
- PJ_ASSERT_RETURN(factory==&ffmpeg_factory.base, PJ_EINVAL);
- PJ_ASSERT_RETURN(info, PJ_EINVAL);
- desc = find_codec_desc_by_info(info);
- if (!desc) {
- return PJMEDIA_CODEC_EUNSUP;
- }
- return PJ_SUCCESS;
- }
- /*
- * Generate default attribute.
- */
- static pj_status_t ffmpeg_default_attr( pjmedia_vid_codec_factory *factory,
- const pjmedia_vid_codec_info *info,
- 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);
- desc = find_codec_desc_by_info(info);
- if (!desc) {
- return PJMEDIA_CODEC_EUNSUP;
- }
- 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;
- /* Encoded format */
- pjmedia_format_init_video(&attr->enc_fmt, desc->info.fmt_id,
- desc->size.w, desc->size.h,
- desc->fps.num, desc->fps.denum);
- /* Decoded format */
- pjmedia_format_init_video(&attr->dec_fmt, desc->info.dec_fmt_id[0],
- desc->size.w, desc->size.h,
- desc->fps.num, desc->fps.denum);
- /* Decoding fmtp */
- attr->dec_fmtp = desc->dec_fmtp;
- /* Bitrate */
- attr->enc_fmt.det.vid.avg_bps = desc->avg_bps;
- attr->enc_fmt.det.vid.max_bps = desc->max_bps;
- /* Encoding MTU */
- attr->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;
- return PJ_SUCCESS;
- }
- /*
- * Enum codecs supported by this factory.
- */
- static pj_status_t ffmpeg_enum_codecs( pjmedia_vid_codec_factory *factory,
- unsigned *count,
- pjmedia_vid_codec_info codecs[])
- {
- unsigned i, max_cnt;
- PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
- PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
- max_cnt = PJ_MIN(*count, PJ_ARRAY_SIZE(codec_desc));
- *count = 0;
- for (i=0; i<max_cnt; ++i) {
- if (codec_desc[i].enabled) {
- pj_memcpy(&codecs[*count], &codec_desc[i].info,
- sizeof(pjmedia_vid_codec_info));
- (*count)++;
- }
- }
- return PJ_SUCCESS;
- }
- /*
- * Allocate a new codec instance.
- */
- static pj_status_t ffmpeg_alloc_codec( pjmedia_vid_codec_factory *factory,
- const pjmedia_vid_codec_info *info,
- pjmedia_vid_codec **p_codec)
- {
- ffmpeg_private *ff;
- const ffmpeg_codec_desc *desc;
- pjmedia_vid_codec *codec;
- pj_pool_t *pool = NULL;
- pj_status_t status = PJ_SUCCESS;
- PJ_ASSERT_RETURN(factory && info && p_codec, PJ_EINVAL);
- PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
- desc = find_codec_desc_by_info(info);
- if (!desc) {
- return PJMEDIA_CODEC_EUNSUP;
- }
- /* Create pool for codec instance */
- pool = pj_pool_create(ffmpeg_factory.pf, "ffmpeg codec", 512, 512, NULL);
- if (!pool) {
- status = PJ_ENOMEM;
- goto on_error;
- }
- codec = PJ_POOL_ZALLOC_T(pool, pjmedia_vid_codec);
- if (!codec) {
- status = PJ_ENOMEM;
- goto on_error;
- }
- codec->op = &ffmpeg_op;
- codec->factory = factory;
- ff = PJ_POOL_ZALLOC_T(pool, ffmpeg_private);
- if (!ff) {
- status = PJ_ENOMEM;
- goto on_error;
- }
- codec->codec_data = ff;
- ff->pool = pool;
- ff->enc = desc->enc;
- ff->dec = desc->dec;
- ff->desc = desc;
- *p_codec = codec;
- return PJ_SUCCESS;
- on_error:
- if (pool)
- pj_pool_release(pool);
- return status;
- }
- /*
- * Free codec.
- */
- static pj_status_t ffmpeg_dealloc_codec( pjmedia_vid_codec_factory *factory,
- pjmedia_vid_codec *codec )
- {
- ffmpeg_private *ff;
- pj_pool_t *pool;
- PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
- PJ_ASSERT_RETURN(factory == &ffmpeg_factory.base, PJ_EINVAL);
- /* Close codec, if it's not closed. */
- ff = (ffmpeg_private*) codec->codec_data;
- pool = ff->pool;
- codec->codec_data = NULL;
- pj_pool_release(pool);
- return PJ_SUCCESS;
- }
- /*
- * Init codec.
- */
- static pj_status_t ffmpeg_codec_init( pjmedia_vid_codec *codec,
- pj_pool_t *pool )
- {
- PJ_UNUSED_ARG(codec);
- PJ_UNUSED_ARG(pool);
- return PJ_SUCCESS;
- }
- static void print_ffmpeg_err(int err)
- {
- #if LIBAVCODEC_VER_AT_LEAST(52,72)
- char errbuf[512];
- if (av_strerror(err, errbuf, sizeof(errbuf)) >= 0)
- PJ_LOG(5, (THIS_FILE, "ffmpeg err %d: %s", err, errbuf));
- #else
- PJ_LOG(5, (THIS_FILE, "ffmpeg err %d", err));
- #endif
- }
- static pj_status_t open_ffmpeg_codec(ffmpeg_private *ff,
- pj_mutex_t *ff_mutex)
- {
- enum AVPixelFormat pix_fmt;
- pjmedia_video_format_detail *vfd;
- pj_bool_t enc_opened = PJ_FALSE, dec_opened = PJ_FALSE;
- pj_status_t status;
- /* Get decoded pixel format */
- status = pjmedia_format_id_to_PixelFormat(ff->param->dec_fmt.id,
- &pix_fmt);
- if (status != PJ_SUCCESS)
- return status;
- ff->expected_dec_fmt = pix_fmt;
- /* Get video format detail for shortcut access to encoded format */
- vfd = pjmedia_format_get_video_format_detail(&ff->param->enc_fmt,
- PJ_TRUE);
- /* Allocate ffmpeg codec context */
- if (ff->param->dir & PJMEDIA_DIR_ENCODING) {
- #if LIBAVCODEC_VER_AT_LEAST(53,20)
- ff->enc_ctx = avcodec_alloc_context3(ff->enc);
- #else
- ff->enc_ctx = avcodec_alloc_context();
- #endif
- if (ff->enc_ctx == NULL)
- goto on_error;
- }
- if (ff->param->dir & PJMEDIA_DIR_DECODING) {
- #if LIBAVCODEC_VER_AT_LEAST(53,20)
- ff->dec_ctx = avcodec_alloc_context3(ff->dec);
- #else
- ff->dec_ctx = avcodec_alloc_context();
- #endif
- if (ff->dec_ctx == NULL)
- goto on_error;
- }
- /* Init generic encoder params */
- if (ff->param->dir & PJMEDIA_DIR_ENCODING) {
- AVCodecContext *ctx = ff->enc_ctx;
- ctx->pix_fmt = pix_fmt;
- ctx->width = vfd->size.w;
- ctx->height = vfd->size.h;
- ctx->time_base.num = vfd->fps.denum;
- ctx->time_base.den = vfd->fps.num;
- if (vfd->avg_bps) {
- ctx->bit_rate = vfd->avg_bps;
- if (vfd->max_bps > vfd->avg_bps)
- ctx->bit_rate_tolerance = vfd->max_bps - vfd->avg_bps;
- }
- ctx->strict_std_compliance = FF_COMPLIANCE_STRICT;
- ctx->workaround_bugs = FF_BUG_AUTODETECT;
- ctx->opaque = ff;
- /* Set no delay, note that this may cause some codec functionals
- * not working (e.g: rate control).
- */
- #if LIBAVCODEC_VER_AT_LEAST(52,113) && !LIBAVCODEC_VER_AT_LEAST(53,20)
- ctx->rc_lookahead = 0;
- #endif
- }
- /* Init generic decoder params */
- if (ff->param->dir & PJMEDIA_DIR_DECODING) {
- AVCodecContext *ctx = ff->dec_ctx;
- /* Width/height may be overriden by ffmpeg after first decoding. */
- ctx->width = ctx->coded_width = ff->param->dec_fmt.det.vid.size.w;
- ctx->height = ctx->coded_height = ff->param->dec_fmt.det.vid.size.h;
- ctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL;
- ctx->workaround_bugs = FF_BUG_AUTODETECT;
- ctx->opaque = ff;
- }
- /* Override generic params or apply specific params before opening
- * the codec.
- */
- if (ff->desc->preopen) {
- status = (*ff->desc->preopen)(ff);
- if (status != PJ_SUCCESS)
- goto on_error;
- }
- /* Open encoder */
- if (ff->param->dir & PJMEDIA_DIR_ENCODING) {
- int err;
- pj_mutex_lock(ff_mutex);
- err = AVCODEC_OPEN(ff->enc_ctx, ff->enc);
- pj_mutex_unlock(ff_mutex);
- if (err < 0) {
- print_ffmpeg_err(err);
- status = PJMEDIA_CODEC_EFAILED;
- goto on_error;
- }
- enc_opened = PJ_TRUE;
- }
- /* Open decoder */
- if (ff->param->dir & PJMEDIA_DIR_DECODING) {
- int err;
- pj_mutex_lock(ff_mutex);
- err = AVCODEC_OPEN(ff->dec_ctx, ff->dec);
- pj_mutex_unlock(ff_mutex);
- if (err < 0) {
- print_ffmpeg_err(err);
- status = PJMEDIA_CODEC_EFAILED;
- goto on_error;
- }
- dec_opened = PJ_TRUE;
- }
- /* Let the codec apply specific params after the codec opened */
- if (ff->desc->postopen) {
- status = (*ff->desc->postopen)(ff);
- if (status != PJ_SUCCESS)
- goto on_error;
- }
- return PJ_SUCCESS;
- on_error:
- if (ff->enc_ctx) {
- if (enc_opened)
- avcodec_close(ff->enc_ctx);
- av_free(ff->enc_ctx);
- ff->enc_ctx = NULL;
- }
- if (ff->dec_ctx) {
- if (dec_opened)
- avcodec_close(ff->dec_ctx);
- av_free(ff->dec_ctx);
- ff->dec_ctx = NULL;
- }
- return status;
- }
- /*
- * Open codec.
- */
- static pj_status_t ffmpeg_codec_open( pjmedia_vid_codec *codec,
- pjmedia_vid_codec_param *attr )
- {
- ffmpeg_private *ff;
- pj_status_t status;
- pj_mutex_t *ff_mutex;
- PJ_ASSERT_RETURN(codec && attr, PJ_EINVAL);
- ff = (ffmpeg_private*)codec->codec_data;
- ff->param = pjmedia_vid_codec_param_clone(ff->pool, attr);
- /* Normalize encoding MTU in codec param */
- if (ff->param->enc_mtu > PJMEDIA_MAX_VID_PAYLOAD_SIZE)
- ff->param->enc_mtu = PJMEDIA_MAX_VID_PAYLOAD_SIZE;
- /* Open the codec */
- ff_mutex = ((struct ffmpeg_factory*)codec->factory)->mutex;
- status = open_ffmpeg_codec(ff, ff_mutex);
- if (status != PJ_SUCCESS)
- goto on_error;
- /* Init format info and apply-param of decoder */
- ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param->dec_fmt.id);
- if (!ff->dec_vfi) {
- status = PJ_EINVAL;
- goto on_error;
- }
- pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
- ff->dec_vafp.size = ff->param->dec_fmt.det.vid.size;
- ff->dec_vafp.buffer = NULL;
- status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
- if (status != PJ_SUCCESS) {
- goto on_error;
- }
- /* Init format info and apply-param of encoder */
- ff->enc_vfi = pjmedia_get_video_format_info(NULL, ff->param->dec_fmt.id);
- if (!ff->enc_vfi) {
- status = PJ_EINVAL;
- goto on_error;
- }
- pj_bzero(&ff->enc_vafp, sizeof(ff->enc_vafp));
- ff->enc_vafp.size = ff->param->enc_fmt.det.vid.size;
- ff->enc_vafp.buffer = NULL;
- status = (*ff->enc_vfi->apply_fmt)(ff->enc_vfi, &ff->enc_vafp);
- if (status != PJ_SUCCESS) {
- goto on_error;
- }
- /* Alloc buffers if needed */
- ff->whole = (ff->param->packing == PJMEDIA_VID_PACKING_WHOLE);
- if (!ff->whole) {
- ff->enc_buf_size = (unsigned)ff->enc_vafp.framebytes;
- ff->enc_buf = pj_pool_alloc(ff->pool, ff->enc_buf_size);
- ff->dec_buf_size = PJ_MAX((unsigned)ff->dec_vafp.framebytes, ff->dec_buf_size);
- 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.
- */
- pj_memcpy(attr, ff->param, sizeof(*attr));
- return PJ_SUCCESS;
- on_error:
- ffmpeg_codec_close(codec);
- return status;
- }
- /*
- * Close codec.
- */
- static pj_status_t ffmpeg_codec_close( pjmedia_vid_codec *codec )
- {
- ffmpeg_private *ff;
- pj_mutex_t *ff_mutex;
- PJ_ASSERT_RETURN(codec, PJ_EINVAL);
- ff = (ffmpeg_private*)codec->codec_data;
- ff_mutex = ((struct ffmpeg_factory*)codec->factory)->mutex;
- pj_mutex_lock(ff_mutex);
- if (ff->enc_ctx) {
- avcodec_close(ff->enc_ctx);
- av_free(ff->enc_ctx);
- }
- if (ff->dec_ctx && ff->dec_ctx!=ff->enc_ctx) {
- avcodec_close(ff->dec_ctx);
- av_free(ff->dec_ctx);
- }
- ff->enc_ctx = NULL;
- ff->dec_ctx = NULL;
- pj_mutex_unlock(ff_mutex);
- return PJ_SUCCESS;
- }
- /*
- * Modify codec settings.
- */
- static pj_status_t ffmpeg_codec_modify( pjmedia_vid_codec *codec,
- const pjmedia_vid_codec_param *attr)
- {
- ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
- PJ_UNUSED_ARG(attr);
- PJ_UNUSED_ARG(ff);
- return PJ_ENOTSUP;
- }
- static pj_status_t ffmpeg_codec_get_param(pjmedia_vid_codec *codec,
- pjmedia_vid_codec_param *param)
- {
- ffmpeg_private *ff;
- PJ_ASSERT_RETURN(codec && param, PJ_EINVAL);
- ff = (ffmpeg_private*)codec->codec_data;
- pj_memcpy(param, ff->param, sizeof(*param));
- return PJ_SUCCESS;
- }
- static pj_status_t ffmpeg_packetize ( pjmedia_vid_codec *codec,
- pj_uint8_t *bits,
- pj_size_t bits_len,
- unsigned *bits_pos,
- pj_uint8_t *payload,
- pj_size_t *payload_len,
- pj_bool_t is_keyframe)
- {
- ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
- if (ff->desc->packetize) {
- return (*ff->desc->packetize)(ff, bits, bits_len, bits_pos,
- payload, payload_len, is_keyframe);
- }
- return PJ_ENOTSUP;
- }
- static pj_status_t ffmpeg_unpacketize(pjmedia_vid_codec *codec,
- const pj_uint8_t *payload,
- pj_size_t payload_len,
- pj_uint8_t *bits,
- pj_size_t bits_len,
- unsigned *bits_pos)
- {
- ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
- if (ff->desc->unpacketize) {
- return (*ff->desc->unpacketize)(ff, payload, payload_len,
- bits, bits_len, bits_pos);
- }
- return PJ_ENOTSUP;
- }
- /*
- * Encode frames.
- */
- static pj_status_t ffmpeg_codec_encode_whole(pjmedia_vid_codec *codec,
- const pjmedia_vid_encode_opt *opt,
- 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;
- AVFrame avframe;
- AVPacket avpacket;
- int err, got_packet;
- //AVRational src_timebase;
- /* For some reasons (e.g: SSE/MMX usage), the avcodec_encode_video() must
- * have stack aligned to 16 bytes. Let's try to be safe by preparing the
- * 16-bytes aligned stack here, in case it's not managed by the ffmpeg.
- */
- PJ_ALIGN_DATA(pj_uint32_t i[4], 16);
- if ((long)(pj_ssize_t)i & 0xF) {
- PJ_LOG(2,(THIS_FILE, "Stack alignment fails"));
- }
- /* Check if encoder has been opened */
- PJ_ASSERT_RETURN(ff->enc_ctx, PJ_EINVALIDOP);
- #ifdef PJMEDIA_USE_OLD_FFMPEG
- avcodec_get_frame_defaults(&avframe);
- #else
- pj_bzero(&avframe, sizeof(avframe));
- av_frame_unref(&avframe);
- #endif
- // Let ffmpeg manage the timestamps
- /*
- src_timebase.num = 1;
- src_timebase.den = ff->desc->info.clock_rate;
- avframe.pts = av_rescale_q(input->timestamp.u64, src_timebase,
- ff->enc_ctx->time_base);
- */
- for (i[0] = 0; i[0] < ff->enc_vfi->plane_cnt; ++i[0]) {
- avframe.data[i[0]] = p;
- avframe.linesize[i[0]] = ff->enc_vafp.strides[i[0]];
- p += ff->enc_vafp.plane_bytes[i[0]];
- }
- #if LIBAVCODEC_VER_AT_LEAST(58,134)
- avframe.height = ff->enc_ctx->height;
- avframe.width = ff->enc_ctx->width;
- avframe.format = ff->enc_ctx->pix_fmt;
- #endif
- /* Force keyframe */
- if (opt && opt->force_keyframe) {
- #if LIBAVCODEC_VER_AT_LEAST(53,20)
- avframe.pict_type = AV_PICTURE_TYPE_I;
- #else
- avframe.pict_type = FF_I_TYPE;
- #endif
- }
- av_init_packet(&avpacket);
- avpacket.data = (pj_uint8_t*)output->buf;
- avpacket.size = output_buf_len;
- #if LIBAVCODEC_VER_AT_LEAST(58,137)
- PJ_UNUSED_ARG(got_packet);
- err = avcodec_send_frame(ff->enc_ctx, &avframe);
- if (err >= 0) {
- AVPacket *pkt = NULL;
- pj_uint8_t *bits_out = (pj_uint8_t*) output->buf;
- unsigned out_size = 0;
- pkt = av_packet_alloc();
- if (pkt) {
- while (err >= 0) {
- err = avcodec_receive_packet(ff->enc_ctx, pkt);
- if (err == AVERROR(EAGAIN) || err == AVERROR_EOF) {
- err = out_size;
- break;
- }
- if (err >= 0) {
- pj_memcpy(bits_out, pkt->data, pkt->size);
- bits_out += pkt->size;
- out_size += pkt->size;
- av_packet_unref(&avpacket);
- }
- }
- av_packet_free(&pkt);
- }
- }
- #elif LIBAVCODEC_VER_AT_LEAST(54,15)
- err = avcodec_encode_video2(ff->enc_ctx, &avpacket, &avframe, &got_packet);
- if (!err && got_packet)
- err = avpacket.size;
- #else
- PJ_UNUSED_ARG(got_packet);
- err = avcodec_encode_video(ff->enc_ctx, avpacket.data, avpacket.size, &avframe);
- #endif
- if (err < 0) {
- print_ffmpeg_err(err);
- return PJMEDIA_CODEC_EFAILED;
- } else {
- pj_bool_t has_key_frame = PJ_FALSE;
- output->size = err;
- output->bit_info = 0;
- #if LIBAVCODEC_VER_AT_LEAST(54,15)
- has_key_frame = (avpacket.flags & AV_PKT_FLAG_KEY);
- #else
- has_key_frame = ff->enc_ctx->coded_frame->key_frame;
- #endif
- if (has_key_frame)
- output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
- }
- return PJ_SUCCESS;
- }
- static pj_status_t ffmpeg_codec_encode_begin(pjmedia_vid_codec *codec,
- const pjmedia_vid_encode_opt *opt,
- 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, opt, input, out_size, output);
- } else {
- pjmedia_frame whole_frm;
- 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, opt, input,
- (unsigned)whole_frm.size,
- &whole_frm);
- if (status != PJ_SUCCESS)
- return status;
- ff->enc_buf_is_keyframe = (whole_frm.bit_info &
- PJMEDIA_VID_FRM_KEYFRAME);
- ff->enc_frame_len = (unsigned)whole_frm.size;
- ff->enc_processed = 0;
- status = ffmpeg_codec_encode_more(codec, out_size, output, has_more);
- }
- 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;
- pj_uint8_t *payload = (pj_uint8_t *)output->buf;
- pj_size_t payload_len = (pj_size_t) out_size;
- 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, ff->enc_buf_is_keyframe);
- if (status != PJ_SUCCESS)
- return status;
- output->type = PJMEDIA_FRAME_TYPE_VIDEO;
- output->size = payload_len;
- if (ff->enc_buf_is_keyframe)
- output->bit_info |= PJMEDIA_VID_FRM_KEYFRAME;
- *has_more = (ff->enc_processed < ff->enc_frame_len);
- return PJ_SUCCESS;
- }
- static pj_status_t check_decode_result(pjmedia_vid_codec *codec,
- const pj_timestamp *ts,
- pj_bool_t got_keyframe)
- {
- ffmpeg_private *ff = (ffmpeg_private*)codec->codec_data;
- pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
- pjmedia_event event;
- /* Check for format change.
- * Decoder output format is set by libavcodec, in case it is different
- * to the configured param.
- */
- if (ff->dec_ctx->pix_fmt != ff->expected_dec_fmt ||
- ff->dec_ctx->width != (int)vafp->size.w ||
- ff->dec_ctx->height != (int)vafp->size.h)
- {
- pjmedia_format_id new_fmt_id;
- pj_status_t status;
- /* Get current raw format id from ffmpeg decoder context */
- status = PixelFormat_to_pjmedia_format_id(ff->dec_ctx->pix_fmt,
- &new_fmt_id);
- if (status != PJ_SUCCESS)
- return status;
- /* Update decoder format in param */
- ff->param->dec_fmt.id = new_fmt_id;
- ff->param->dec_fmt.det.vid.size.w = ff->dec_ctx->width;
- ff->param->dec_fmt.det.vid.size.h = ff->dec_ctx->height;
- ff->expected_dec_fmt = ff->dec_ctx->pix_fmt;
- /* Re-init format info and apply-param of decoder */
- ff->dec_vfi = pjmedia_get_video_format_info(NULL, ff->param->dec_fmt.id);
- if (!ff->dec_vfi)
- return PJ_ENOTSUP;
- pj_bzero(&ff->dec_vafp, sizeof(ff->dec_vafp));
- ff->dec_vafp.size = ff->param->dec_fmt.det.vid.size;
- ff->dec_vafp.buffer = NULL;
- status = (*ff->dec_vfi->apply_fmt)(ff->dec_vfi, &ff->dec_vafp);
- 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 = (unsigned)ff->dec_vafp.framebytes;
- ff->dec_buf = pj_pool_alloc(ff->pool, ff->dec_buf_size);
- }
- /* Broadcast format changed event */
- pjmedia_event_init(&event, PJMEDIA_EVENT_FMT_CHANGED, ts, codec);
- event.data.fmt_changed.dir = PJMEDIA_DIR_DECODING;
- pj_memcpy(&event.data.fmt_changed.new_fmt, &ff->param->dec_fmt,
- sizeof(ff->param->dec_fmt));
- pjmedia_event_publish(NULL, codec, &event, 0);
- }
- /* Check for missing/found keyframe */
- if (got_keyframe) {
- pj_get_timestamp(&ff->last_dec_keyframe_ts);
- /* Broadcast keyframe event */
- pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_FOUND, ts, codec);
- pjmedia_event_publish(NULL, codec, &event, 0);
- } else if (ff->last_dec_keyframe_ts.u64 == 0) {
- /* Broadcast missing keyframe event */
- pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING, ts, codec);
- pjmedia_event_publish(NULL, codec, &event, 0);
- }
- return PJ_SUCCESS;
- }
- /*
- * Unreference AVFrame.
- */
- static void ffmpeg_frame_unref(AVFrame *frame)
- {
- #ifdef PJMEDIA_USE_OLD_FFMPEG
- (void)frame;
- #else
- av_frame_unref(frame);
- #endif
- }
- /*
- * Decode frame.
- */
- 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;
- AVPacket avpacket;
- int err, got_picture;
- /* Check if decoder has been opened */
- PJ_ASSERT_RETURN(ff->dec_ctx, PJ_EINVALIDOP);
- /* Reset output frame bit info */
- output->bit_info = 0;
- /* Validate output buffer size */
- // Do this validation later after getting decoding result, where the real
- // decoded size will be assured.
- //if (ff->dec_vafp.framebytes > output_buf_len)
- //return PJ_ETOOSMALL;
- /* Init frame to receive the decoded data, the ffmpeg codec context will
- * automatically provide the decoded buffer (single buffer used for the
- * whole decoding session, and seems to be freed when the codec context
- * closed).
- */
- #ifdef PJMEDIA_USE_OLD_FFMPEG
- avcodec_get_frame_defaults(&avframe);
- #else
- pj_bzero(&avframe, sizeof(avframe));
- av_frame_unref(&avframe);
- #endif
- /* Init packet, the container of the encoded data */
- av_init_packet(&avpacket);
- avpacket.data = (pj_uint8_t*)input->buf;
- avpacket.size = (int)input->size;
- /* ffmpeg warns:
- * - input buffer padding, at least FF_INPUT_BUFFER_PADDING_SIZE
- * - null terminated
- * Normally, encoded buffer is allocated more than needed, so lets just
- * bzero the input buffer end/pad, hope it will be just fine.
- */
- #if LIBAVCODEC_VER_AT_LEAST(56,35)
- /* 2015-07-27 - lavc 56.56.100 / 56.35.0 - avcodec.h
- * 29d147c / 059a9348
- * - Rename FF_INPUT_BUFFER_PADDING_SIZE and FF_MIN_BUFFER_SIZE
- * to AV_INPUT_BUFFER_PADDING_SIZE and AV_INPUT_BUFFER_MIN_SIZE.
- */
- pj_bzero(avpacket.data+avpacket.size, AV_INPUT_BUFFER_PADDING_SIZE);
- #else
- pj_bzero(avpacket.data+avpacket.size, FF_INPUT_BUFFER_PADDING_SIZE);
- #endif
- output->bit_info = 0;
- output->timestamp = input->timestamp;
- #if LIBAVCODEC_VER_AT_LEAST(52,72)
- //avpacket.flags = AV_PKT_FLAG_KEY;
- #else
- avpacket.flags = 0;
- #endif
- #if LIBAVCODEC_VER_AT_LEAST(58,137)
- err = avcodec_send_packet(ff->dec_ctx, &avpacket);
- if (err >= 0) {
- err = avcodec_receive_frame(ff->dec_ctx, &avframe);
- if (err == AVERROR_EOF)
- err = 0;
- if (err >= 0) {
- got_picture = PJ_TRUE;
- }
- }
- #elif LIBAVCODEC_VER_AT_LEAST(52,72)
- err = avcodec_decode_video2(ff->dec_ctx, &avframe,
- &got_picture, &avpacket);
- #else
- err = avcodec_decode_video(ff->dec_ctx, &avframe,
- &got_picture, avpacket.data, avpacket.size);
- #endif
- if (err < 0) {
- pjmedia_event event;
- output->type = PJMEDIA_FRAME_TYPE_NONE;
- output->size = 0;
- print_ffmpeg_err(err);
- /* Broadcast missing keyframe event */
- pjmedia_event_init(&event, PJMEDIA_EVENT_KEYFRAME_MISSING,
- &input->timestamp, codec);
- pjmedia_event_publish(NULL, codec, &event, 0);
- return PJMEDIA_CODEC_EBADBITSTREAM;
- } else if (got_picture) {
- pjmedia_video_apply_fmt_param *vafp = &ff->dec_vafp;
- pj_uint8_t *q = (pj_uint8_t*)output->buf;
- unsigned i;
- pj_status_t status;
- /* Check decoding result, e.g: see if the format got changed,
- * keyframe found/missing.
- */
- status = check_decode_result(codec, &input->timestamp,
- avframe.key_frame);
- if (status != PJ_SUCCESS) {
- ffmpeg_frame_unref(&avframe);
- return status;
- }
- /* Check provided buffer size */
- if (vafp->framebytes > output_buf_len) {
- ffmpeg_frame_unref(&avframe);
- return PJ_ETOOSMALL;
- }
- /* Get the decoded data */
- for (i = 0; i < ff->dec_vfi->plane_cnt; ++i) {
- pj_uint8_t *p = avframe.data[i];
- /* The decoded data may contain padding */
- if (avframe.linesize[i]!=vafp->strides[i]) {
- /* Padding exists, copy line by line */
- pj_uint8_t *q_end;
- q_end = q+vafp->plane_bytes[i];
- while(q < q_end) {
- pj_memcpy(q, p, vafp->strides[i]);
- q += vafp->strides[i];
- p += avframe.linesize[i];
- }
- } else {
- /* No padding, copy the whole plane */
- pj_memcpy(q, p, vafp->plane_bytes[i]);
- q += vafp->plane_bytes[i];
- }
- }
- output->type = PJMEDIA_FRAME_TYPE_VIDEO;
- output->size = vafp->framebytes;
- ffmpeg_frame_unref(&avframe);
- } else {
- output->type = PJMEDIA_FRAME_TYPE_NONE;
- output->size = 0;
- }
- 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")
- #endif
- #endif /* PJMEDIA_HAS_FFMPEG_VID_CODEC */
|