{"id":579,"date":"2016-03-29T11:58:25","date_gmt":"2016-03-29T11:58:25","guid":{"rendered":"http:\/\/blogs.gentoo.org\/lu_zero\/?p=579"},"modified":"2016-04-01T03:50:55","modified_gmt":"2016-04-01T03:50:55","slug":"new-avcodec-api","status":"publish","type":"post","link":"https:\/\/blogs.gentoo.org\/lu_zero\/2016\/03\/29\/new-avcodec-api\/","title":{"rendered":"New AVCodec API"},"content":{"rendered":"<p>Another week another API landed in the tree and since I spent <a href=\"https:\/\/blogs.gentoo.org\/lu_zero\/2015\/03\/23\/decoupling-an-api\/\">some<\/a> <a href=\"https:\/\/blogs.gentoo.org\/lu_zero\/2015\/10\/02\/decoupling-an-api-part-ii\/\">time<\/a> drafting it, I guess I should describe how to use it now what is implemented. This is part I<\/p>\n<h2>What is here now<\/h2>\n<p>Between theory and practice there is a bit of discussion and obviously the (lack) of time to implement, so here what is different from what I drafted originally:<\/p>\n<ul>\n<li>Function Names: <strong>push<\/strong> got renamed to <strong>send<\/strong> and <strong>pull<\/strong> got renamed to <strong>receive<\/strong>.<\/li>\n<li>No separated function to probe the process state, <strong>need_data<\/strong> and <strong>have_data<\/strong> are not here.<\/li>\n<li>No codecs ported to use the new API, so no actual asyncronicity for now.<\/li>\n<li>Subtitles aren&#8217;t supported yet.<\/li>\n<\/ul>\n<h2>New API<\/h2>\n<p>There are just 4 new functions replacing both audio-specific and video-specific ones:<\/p>\n<div class=\"codehilite\">\n<pre><span class=\"c1\">\/\/ Decode<\/span>\n<span class=\"kt\">int<\/span> <span class=\"nf\">avcodec_send_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"k\">const<\/span> <span class=\"n\">AVPacket<\/span> <span class=\"o\">*<\/span><span class=\"n\">avpkt<\/span><span class=\"p\">);<\/span>\n<span class=\"kt\">int<\/span> <span class=\"nf\">avcodec_receive_frame<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n\n<span class=\"c1\">\/\/ Encode<\/span>\n<span class=\"kt\">int<\/span> <span class=\"nf\">avcodec_send_frame<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"k\">const<\/span> <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n<span class=\"kt\">int<\/span> <span class=\"nf\">avcodec_receive_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVPacket<\/span> <span class=\"o\">*<\/span><span class=\"n\">avpkt<\/span><span class=\"p\">);<\/span>\n<\/pre>\n<\/div>\n<p>The workflow is sort of simple:<br \/>\n&#8211; You setup the decoder or the encoder as usual<br \/>\n&#8211; You feed data using the <code>avcodec_send_*<\/code> functions until you get a <code>AVERROR(EAGAIN)<\/code>, that signals that the internal input buffer is full.<br \/>\n&#8211; You get the data back using the matching <code>avcodec_receive_*<\/code> function until you get a <code>AVERROR(EAGAIN)<\/code>, signalling that the internal output buffer is empty.<br \/>\n&#8211; Once you are done feeding data you have to pass a NULL to signal the end of stream.<br \/>\n&#8211; You can keep calling the <code>avcodec_receive_*<\/code> function until you get <code>AVERROR_EOF<\/code>.<br \/>\n&#8211; You free the contexts as usual.<\/p>\n<h2>Decoding examples<\/h2>\n<h3>Setup<\/h3>\n<p>The setup uses the usual <code>avcodec_open2<\/code>.<\/p>\n<div class=\"codehilite\">\n<pre>    <span class=\"p\">...<\/span>\n\n    <span class=\"n\">c<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_alloc_context3<\/span><span class=\"p\">(<\/span><span class=\"n\">codec<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_open2<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">,<\/span> <span class=\"n\">codec<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">opts<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">...<\/span>\n<\/pre>\n<\/div>\n<h3>Simple decoding loop<\/h3>\n<p>People using the old API usually have some kind of simple loop like<\/p>\n<div class=\"codehilite\">\n<pre><span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"n\">get_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">pkt<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_decode_video2<\/span><span class=\"p\">(<\/span><span class=\"n\">c<\/span><span class=\"p\">,<\/span> <span class=\"n\">picture<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">got_picture<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"p\">...<\/span>\n    <span class=\"p\">}<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">got_picture<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"p\">...<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/pre>\n<\/div>\n<p>The old functions can be replaced by calling something like the following.<\/p>\n<div class=\"codehilite\">\n<pre><span class=\"c1\">\/\/ The flush packet is a non-NULL packet with size 0 and data NULL<\/span>\n<span class=\"kt\">int<\/span> <span class=\"nf\">decode<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span><span class=\"p\">,<\/span> <span class=\"kt\">int<\/span> <span class=\"o\">*<\/span><span class=\"n\">got_frame<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVPacket<\/span> <span class=\"o\">*<\/span><span class=\"n\">pkt<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"kt\">int<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"o\">*<\/span><span class=\"n\">got_frame<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">pkt<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_send_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n        <span class=\"c1\">\/\/ In particular, we don&#039;t expect AVERROR(EAGAIN), because we read all<\/span>\n        <span class=\"c1\">\/\/ decoded frames with avcodec_receive_frame() until done.<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span> <span class=\"o\">==<\/span> <span class=\"n\">AVERROR_EOF<\/span> <span class=\"o\">?<\/span> <span class=\"mi\">0<\/span> <span class=\"o\">:<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_receive_frame<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"n\">ret<\/span> <span class=\"o\">!=<\/span> <span class=\"n\">AVERROR<\/span><span class=\"p\">(<\/span><span class=\"n\">EAGAIN<\/span><span class=\"p\">)<\/span> <span class=\"o\">&amp;&amp;<\/span> <span class=\"n\">ret<\/span> <span class=\"o\">!=<\/span> <span class=\"n\">AVERROR_EOF<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n        <span class=\"o\">*<\/span><span class=\"n\">got_frame<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/pre>\n<\/div>\n<h3>Callback approach<\/h3>\n<p>Since the new API will output multiple frames in certain situations would be better to process them as they are produced.<\/p>\n<div class=\"codehilite\">\n<pre><span class=\"c1\">\/\/ return 0 on success, negative on error<\/span>\n<span class=\"k\">typedef<\/span> <span class=\"nf\">int<\/span> <span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">process_frame_cb<\/span><span class=\"p\">)(<\/span><span class=\"kt\">void<\/span> <span class=\"o\">*<\/span><span class=\"n\">ctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n\n<span class=\"kt\">int<\/span> <span class=\"nf\">decode<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">pkt<\/span><span class=\"p\">,<\/span>\n           <span class=\"n\">process_frame_cb<\/span> <span class=\"n\">cb<\/span><span class=\"p\">,<\/span> <span class=\"kt\">void<\/span> <span class=\"o\">*<\/span><span class=\"n\">priv<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span> <span class=\"o\">=<\/span> <span class=\"n\">av_frame_alloc<\/span><span class=\"p\">();<\/span>\n    <span class=\"kt\">int<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_send_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n    <span class=\"c1\">\/\/ Again EAGAIN is not expected<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">goto<\/span> <span class=\"n\">out<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_receive_frame<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">cb<\/span><span class=\"p\">(<\/span><span class=\"n\">priv<\/span><span class=\"p\">,<\/span> <span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"nl\">out<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">av_frame_free<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">==<\/span> <span class=\"n\">AVERROR<\/span><span class=\"p\">(<\/span><span class=\"n\">EAGAIN<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">return<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/pre>\n<\/div>\n<h3>Separated threads<\/h3>\n<p>The new API makes sort of easy to split the workload in two separated threads.<\/p>\n<div class=\"codehilite\">\n<pre><span class=\"c1\">\/\/ Assume we have context with a mutex, a condition variable and the AVCodecContext<\/span>\n\n\n<span class=\"c1\">\/\/ Feeding loop<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"n\">AVPacket<\/span> <span class=\"o\">*<\/span><span class=\"n\">pkt<\/span> <span class=\"o\">=<\/span> <span class=\"nb\">NULL<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">while<\/span> <span class=\"p\">((<\/span><span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">get_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">ctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">))<\/span> <span class=\"o\">&gt;=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">pthread_mutex_lock<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">lock<\/span><span class=\"p\">);<\/span>\n\n        <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_send_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">pthread_cond_signal<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">cond<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">==<\/span> <span class=\"n\">AVERROR<\/span><span class=\"p\">(<\/span><span class=\"n\">EAGAIN<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ Signal the draining loop<\/span>\n            <span class=\"n\">pthread_cond_signal<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">cond<\/span><span class=\"p\">);<\/span>\n            <span class=\"c1\">\/\/ Wait here<\/span>\n            <span class=\"n\">pthread_cond_wait<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">cond<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">mutex<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">goto<\/span> <span class=\"n\">out<\/span><span class=\"p\">;<\/span>\n\n        <span class=\"n\">pthread_mutex_unlock<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">lock<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"n\">pthread_mutex_lock<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">lock<\/span><span class=\"p\">);<\/span>\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_send_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"nb\">NULL<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"n\">pthread_cond_signal<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">cond<\/span><span class=\"p\">);<\/span>\n\n<span class=\"nl\">out<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">pthread_mutex_unlock<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">lock<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ Draining loop<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span> <span class=\"o\">=<\/span> <span class=\"n\">av_frame_alloc<\/span><span class=\"p\">();<\/span>\n\n    <span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">done<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">pthread_mutex_lock<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">lock<\/span><span class=\"p\">);<\/span>\n\n        <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_receive_frame<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">pthread_cond_signal<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">cond<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">==<\/span> <span class=\"n\">AVERROR<\/span><span class=\"p\">(<\/span><span class=\"n\">EAGAIN<\/span><span class=\"p\">))<\/span> <span class=\"p\">{<\/span>\n            <span class=\"c1\">\/\/ Signal the feeding loop<\/span>\n            <span class=\"n\">pthread_cond_signal<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">cond<\/span><span class=\"p\">);<\/span>\n            <span class=\"c1\">\/\/ Wait<\/span>\n            <span class=\"n\">pthread_cond_wait<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">cond<\/span><span class=\"p\">,<\/span> <span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">mutex<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span> <span class=\"k\">else<\/span> <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n            <span class=\"k\">goto<\/span> <span class=\"n\">out<\/span><span class=\"p\">;<\/span>\n\n        <span class=\"n\">pthread_mutex_unlock<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">lock<\/span><span class=\"p\">);<\/span>\n\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n            <span class=\"n\">do_something<\/span><span class=\"p\">(<\/span><span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n        <span class=\"p\">}<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"nl\">out<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">pthread_mutex_unlock<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">ctx<\/span><span class=\"o\">-&gt;<\/span><span class=\"n\">lock<\/span><span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/pre>\n<\/div>\n<p>It isn&#8217;t as neat as having all this abstracted away, but is mostly workable.<\/p>\n<h2>Encoding Examples<\/h2>\n<h3>Simple encoding loop<\/h3>\n<p>Some compatibility with the old API can be achieved using something along the lines of:<\/p>\n<div class=\"codehilite\">\n<pre><span class=\"kt\">int<\/span> <span class=\"nf\">encode<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVPacket<\/span> <span class=\"o\">*<\/span><span class=\"n\">pkt<\/span><span class=\"p\">,<\/span> <span class=\"kt\">int<\/span> <span class=\"o\">*<\/span><span class=\"n\">got_packet<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"kt\">int<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"o\">*<\/span><span class=\"n\">got_packet<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_send_frame<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_receive_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span>\n        <span class=\"o\">*<\/span><span class=\"n\">got_packet<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">1<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">==<\/span> <span class=\"n\">AVERROR<\/span><span class=\"p\">(<\/span><span class=\"n\">EAGAIN<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">return<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/pre>\n<\/div>\n<h3>Callback approach<\/h3>\n<p>Since for each input multiple output could be produced, would be better to loop over the output as soon as possible.<\/p>\n<div class=\"codehilite\">\n<pre><span class=\"c1\">\/\/ return 0 on success, negative on error<\/span>\n<span class=\"k\">typedef<\/span> <span class=\"nf\">int<\/span> <span class=\"p\">(<\/span><span class=\"o\">*<\/span><span class=\"n\">process_packet_cb<\/span><span class=\"p\">)(<\/span><span class=\"kt\">void<\/span> <span class=\"o\">*<\/span><span class=\"n\">ctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVPacket<\/span> <span class=\"o\">*<\/span><span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n\n<span class=\"kt\">int<\/span> <span class=\"nf\">encode<\/span><span class=\"p\">(<\/span><span class=\"n\">AVCodecContext<\/span> <span class=\"o\">*<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">AVFrame<\/span> <span class=\"o\">*<\/span><span class=\"n\">frame<\/span><span class=\"p\">,<\/span>\n           <span class=\"n\">process_packet_cb<\/span> <span class=\"n\">cb<\/span><span class=\"p\">,<\/span> <span class=\"kt\">void<\/span> <span class=\"o\">*<\/span><span class=\"n\">priv<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"n\">AVPacket<\/span> <span class=\"o\">*<\/span><span class=\"n\">pkt<\/span> <span class=\"o\">=<\/span> <span class=\"n\">av_packet_alloc<\/span><span class=\"p\">();<\/span>\n    <span class=\"kt\">int<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_send_frame<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">frame<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">&lt;<\/span> <span class=\"mi\">0<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">goto<\/span> <span class=\"n\">out<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">avcodec_receive_packet<\/span><span class=\"p\">(<\/span><span class=\"n\">avctx<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n        <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"o\">!<\/span><span class=\"n\">ret<\/span><span class=\"p\">)<\/span>\n            <span class=\"n\">ret<\/span> <span class=\"o\">=<\/span> <span class=\"n\">cb<\/span><span class=\"p\">(<\/span><span class=\"n\">priv<\/span><span class=\"p\">,<\/span> <span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n\n<span class=\"nl\">out<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">av_packet_free<\/span><span class=\"p\">(<\/span><span class=\"o\">&amp;<\/span><span class=\"n\">pkt<\/span><span class=\"p\">);<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">ret<\/span> <span class=\"o\">==<\/span> <span class=\"n\">AVERROR<\/span><span class=\"p\">(<\/span><span class=\"n\">EAGAIN<\/span><span class=\"p\">))<\/span>\n        <span class=\"k\">return<\/span> <span class=\"mi\">0<\/span><span class=\"p\">;<\/span>\n    <span class=\"k\">return<\/span> <span class=\"n\">ret<\/span><span class=\"p\">;<\/span>\n<span class=\"p\">}<\/span>\n<\/pre>\n<\/div>\n<p>The I\/O should happen in a different thread when possible so the <strong>callback<\/strong> should just enqueue the packets.<\/p>\n<h2>Coming Next<\/h2>\n<p>This post is long enough so the next one might involve converting a codec to the new API.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Another week another API landed in the tree and since I spent some time drafting it, I guess I should describe how to use it now what is implemented. This is part I What is here now Between theory and practice there is a bit of discussion and obviously the (lack) of time to implement, &hellip; <a href=\"https:\/\/blogs.gentoo.org\/lu_zero\/2016\/03\/29\/new-avcodec-api\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">New AVCodec API<\/span><\/a><\/p>\n","protected":false},"author":10,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true},"categories":[14],"tags":[19],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p1aGWH-9l","_links":{"self":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts\/579"}],"collection":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/comments?post=579"}],"version-history":[{"count":6,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts\/579\/revisions"}],"predecessor-version":[{"id":586,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/posts\/579\/revisions\/586"}],"wp:attachment":[{"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/media?parent=579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/categories?post=579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.gentoo.org\/lu_zero\/wp-json\/wp\/v2\/tags?post=579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}