<div dir="ltr">
<div>Hello, <br></div><div><br></div><div>I am trying to use a custom 
AVIOContext to open a wav audio file buffer and read the duration along 
with other audio characteristics.  The example code posted blow shows 2 
methods of opening the same file.  In the case where I call 
avformat_open_input with the audio.wav file saved on disk, I 
consistently get the correct duration.  When I call avformat_open_input 
with the audio.wav file saved as a file buffer using a custom 
AVIOContext, I am not able to get a reasonable value for duration.  <br></div><div><br></div><div>From
 the API documentation, I have tried 3 methods I can find for 
determining duration without luck. I have tried many different test 
files to verify the issue and the duration is either zero or a very 
large negative number.  Are there any other methods of getting the 
duration of an audio stream or am I missing a step before trying to get 
the duration? <br></div><div>
<div><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"Consolas";font-size:9.8pt"><span style="color:rgb(128,128,128);font-style:italic">m_audioInfo->duration = static_cast<double>(pFormatContext->duration) / AV_TIME_BASE;<br></span><span style="color:rgb(128,128,128);font-style:italic">m_audioInfo->duration = (pStream->duration / (1/av_q2d(pStream->time_base)));<br></span>m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>duration = pFormatContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>duration;</pre></div>

</div><div><br></div><div>Any help you can provide would be greatly appreciated. Thank you!  Below is the code that I am using:<br></div><div><br></div><div><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"Consolas";font-size:9.8pt"><span style="color:rgb(0,0,128);font-weight:bold">#include </span><span style="color:rgb(0,128,0);font-weight:bold">"AsyncInspectionWorker.h"<br></span><span style="color:rgb(0,128,0);font-weight:bold"><br></span><span style="color:rgb(102,14,122);font-weight:bold">using namespace </span>v8;<br><span style="color:rgb(102,14,122);font-weight:bold">using namespace </span>std;<br><br><br><span style="color:rgb(0,0,128);font-weight:bold">const </span>size_t EMPTY = <span style="color:rgb(0,0,255)">0</span>;<br><br><span style="color:rgb(128,128,128);font-style:italic">/* User defined data holder that will be passed to avio_alloc_context() */<br></span><span style="color:rgb(0,0,128);font-weight:bold">struct </span>buffer_in_data {<br>   uint8_t* ptr;<br>   size_t size;<br>};<br><br><span style="color:rgb(128,128,128);font-style:italic">/* Function for reading the user defined buffer_in_data structure passed to avio_alloc_context() */<br></span><span style="color:rgb(0,0,128);font-weight:bold">static int </span>read_packet(<span style="color:rgb(0,0,128);font-weight:bold">void</span>* opaque, uint8_t* buf, <span style="color:rgb(0,0,128);font-weight:bold">int </span>buf_size) {<br>   <span style="color:rgb(0,0,128);font-weight:bold">struct </span>buffer_in_data* bd = (<span style="color:rgb(0,0,128);font-weight:bold">struct </span>buffer_in_data*)opaque;<br>   buf_size = FFMIN(buf_size, bd<span style="color:rgb(0,102,102);font-weight:bold">-></span>size);<br><br>   memcpy(buf, bd<span style="color:rgb(0,102,102);font-weight:bold">-></span>ptr, buf_size);<br>   bd<span style="color:rgb(0,102,102);font-weight:bold">-></span>ptr += buf_size;<br>   bd<span style="color:rgb(0,102,102);font-weight:bold">-></span>size -= buf_size;<br><br>   <span style="color:rgb(0,0,128);font-weight:bold">return </span>buf_size;<br>}<br><br>AsyncInspectionWorker::AsyncInspectionWorker(string filename, Nan::Callback *callback)<br> : Nan::AsyncWorker(callback) {<br>    m_filename = filename;<br>   m_buffer_in_size = EMPTY;<br>}<br><br>AsyncInspectionWorker::AsyncInspectionWorker(<span style="color:rgb(0,0,128);font-weight:bold">char</span>* buffer, size_t bufferSize, Nan::Callback* callback)<br> : Nan::AsyncWorker(callback) {<br>   m_buffer_in = buffer;<br>   m_buffer_in_size = bufferSize;<br>}<br><br><span style="color:rgb(0,0,128);font-weight:bold">void </span>AsyncInspectionWorker::Execute() {<br>    AVCodec* pCodec;<br>    AVStream* pStream = NULL;<br>   AVIOContext* avio_ctx = NULL;<br>    AVCodecContext* pCodecContext;<br>    AVCodecContext* pCodecContextOrig;<br>    AVFormatContext* pFormatContext = avformat_alloc_context();<br>   <span style="color:rgb(0,0,128);font-weight:bold">struct </span>buffer_in_data bd = { <span style="color:rgb(0,0,255)">0</span>, <span style="color:rgb(0,0,255)">0</span>};<br><br>   <span style="color:rgb(0,0,128);font-weight:bold">if </span>(m_buffer_in_size != EMPTY) {<br>      <span style="color:rgb(128,128,128);font-style:italic">// This Buffer reading code based on ffmpeg project's doc/examples/avio_reading.c <br></span><span style="color:rgb(128,128,128);font-style:italic">      </span>uint8_t* avio_ctx_buffer = NULL;<br>      size_t avio_ctx_buffer_size = <span style="color:rgb(0,0,255)">4096</span>;<br><br>      bd.ptr = <span style="color:rgb(102,14,122);font-weight:bold">reinterpret_cast</span><uint8_t*>(m_buffer_in);<br>      bd.size = m_buffer_in_size;<br><br>      <span style="color:rgb(0,0,128);font-weight:bold">if </span>(!(avio_ctx_buffer = <span style="color:rgb(102,14,122);font-weight:bold">static_cast</span><uint8_t*>(av_malloc(avio_ctx_buffer_size)))) {<br>         SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unable to allocate enough memory for processing"</span>);<br>         <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>      }<br><br>      <span style="color:rgb(0,0,128);font-weight:bold">if </span>(!(avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size, <span style="color:rgb(0,0,255)">0</span>, &bd, &read_packet, NULL, NULL))) {<br>         SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unable to allocate enough memory for processing"</span>);<br>         <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>      }<br><br>      pFormatContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>pb = avio_ctx;<br>      <br>      <span style="color:rgb(0,0,128);font-weight:bold">if </span>(avformat_open_input(&pFormatContext, NULL, NULL, NULL) < <span style="color:rgb(0,0,255)">0</span>) {<br>         SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unable to read Buffer data"</span>);<br>         <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>      }<br>   } <span style="color:rgb(0,0,128);font-weight:bold">else </span>{<br>      <span style="color:rgb(0,0,128);font-weight:bold">if </span>(avformat_open_input(&pFormatContext, m_filename.c_str(), NULL, NULL) != <span style="color:rgb(0,0,255)">0</span>) {<br>         SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unable to open file"</span>);<br>         <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>      }<br>   }    <br><br>    <span style="color:rgb(0,0,128);font-weight:bold">if </span>(avformat_find_stream_info(pFormatContext, NULL) != <span style="color:rgb(0,0,255)">0</span>) {<br>        SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unable to find stream info"</span>);<br>        <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>    }<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">for </span>(<span style="color:rgb(0,0,128);font-weight:bold">unsigned int </span>i = <span style="color:rgb(0,0,255)">0</span>; i < pFormatContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>nb_streams; i++)<br>    {<br>        <span style="color:rgb(0,0,128);font-weight:bold">if </span>(pFormatContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>streams[i]<span style="color:rgb(0,102,102);font-weight:bold">-></span>codec<span style="color:rgb(0,102,102);font-weight:bold">-></span>codec_type == AVMEDIA_TYPE_AUDIO)<br>        {<br>            pStream = pFormatContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>streams[i];<br>            <span style="color:rgb(0,0,128);font-weight:bold">break</span>;<br>        }<br>    }<br>    <span style="color:rgb(0,0,128);font-weight:bold">if </span>(pStream == NULL) {<br>        SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unable to find audio stream"</span>);<br>        <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>    }<br><br>    pCodecContextOrig = pStream<span style="color:rgb(0,102,102);font-weight:bold">-></span>codec;<br>    pCodec = avcodec_find_decoder(pCodecContextOrig<span style="color:rgb(0,102,102);font-weight:bold">-></span>codec_id);<br>    <span style="color:rgb(0,0,128);font-weight:bold">if </span>(pCodec == NULL) {<br>        SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unsupported codec"</span>);<br>        <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>    }<br><br>    pCodecContext = avcodec_alloc_context3(pCodec);<br>    <span style="color:rgb(0,0,128);font-weight:bold">if </span>(avcodec_copy_context(pCodecContext, pCodecContextOrig) != <span style="color:rgb(0,0,255)">0</span>) {<br>        SetErrorMessage(<span style="color:rgb(0,128,0);font-weight:bold">"Unable to copy codec context"</span>);<br>        <span style="color:rgb(0,0,128);font-weight:bold">return</span>;<br>    }<br>    avcodec_open2(pCodecContext, pCodec, NULL);<br><br>    m_audioInfo = <span style="color:rgb(102,14,122);font-weight:bold">new </span>AudioInfo();<br>    <span style="color:rgb(128,128,128);font-style:italic">//m_audioInfo->duration = static_cast<double>(pFormatContext->duration) / AV_TIME_BASE;<br></span><span style="color:rgb(128,128,128);font-style:italic">    //m_audioInfo->duration = (pStream->duration / (1/av_q2d(pStream->time_base)));<br></span><span style="color:rgb(128,128,128);font-style:italic">    </span>m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>duration = pFormatContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>duration;<br>    m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>sample_rate = pCodecContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>sample_rate;<br>    m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>channels = pCodecContext<span style="color:rgb(0,102,102);font-weight:bold">-></span>channels;<br>   <br>    avcodec_close(pCodecContext);<br>   avcodec_close(pCodecContextOrig);<br>    avformat_close_input(&pFormatContext);<br>   pFormatContext = NULL;<br>   <br>   <span style="color:rgb(0,0,128);font-weight:bold">if </span>(avio_ctx && avio_ctx != NULL) {<br>      av_freep(&avio_ctx<span style="color:rgb(0,102,102);font-weight:bold">-></span>buffer);<br>      avio_context_free(&avio_ctx);<br>   }<br>}<br><br><span style="color:rgb(0,0,128);font-weight:bold">void </span>AsyncInspectionWorker::HandleOKCallback() {<br>    Nan::HandleScope scope;<br>    <span style="color:rgb(0,0,128);font-weight:bold">const int </span>argc = <span style="color:rgb(0,0,255)">1</span>;<br>   Local<Object> audioInfo = Nan::New<Object>();<br><br>    <span style="color:rgb(0,0,128);font-weight:bold">if</span>(m_audioInfo != NULL) {<br>        Nan::Set(audioInfo, Nan::New<String>(<span style="color:rgb(0,128,0);font-weight:bold">"duration"</span>).ToLocalChecked(), Nan::New<Number>(m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>duration));<br>        Nan::Set(audioInfo, Nan::New<String>(<span style="color:rgb(0,128,0);font-weight:bold">"sampleRate"</span>).ToLocalChecked(), Nan::New<Number>(m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>sample_rate));<br>        Nan::Set(audioInfo, Nan::New<String>(<span style="color:rgb(0,128,0);font-weight:bold">"channels"</span>).ToLocalChecked(), Nan::New<Number>(m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>channels));<br>        <span style="color:rgb(128,128,128);font-style:italic">//This inspection reports how the data will look after transcoding, everything is converted to 16 bit (2 bytes)<br></span><span style="color:rgb(128,128,128);font-style:italic">        </span>Nan::Set(audioInfo, Nan::New<String>(<span style="color:rgb(0,128,0);font-weight:bold">"bitRate"</span>).ToLocalChecked(), Nan::New<Number>(<span style="color:rgb(0,0,255)">16</span>));<br>        Nan::Set(audioInfo, Nan::New<String>(<span style="color:rgb(0,128,0);font-weight:bold">"sampleSize"</span>).ToLocalChecked(), Nan::New<Number>(<span style="color:rgb(0,0,255)">2 </span>* m_audioInfo<span style="color:rgb(0,102,102);font-weight:bold">-></span>channels));<br><br>        <span style="color:rgb(0,0,128);font-weight:bold">delete </span>m_audioInfo;<br>    }<br><br>    Local<Value> argv[argc] = {audioInfo};<br>    callback<span style="color:rgb(0,102,102);font-weight:bold">-></span>Call(argc, argv);<br>}<br><br><span style="color:rgb(0,0,128);font-weight:bold">void </span>AsyncInspectionWorker::HandleErrorCallback() {<br>    Nan::HandleScope scope;<br>    <span style="color:rgb(0,0,128);font-weight:bold">const int </span>argc = <span style="color:rgb(0,0,255)">1</span>;<br>   Local<Object> returnObject = Nan::New<Object>();<br><br>    Nan::Set(returnObject, Nan::New<String>(<span style="color:rgb(0,128,0);font-weight:bold">"error"</span>).ToLocalChecked(), Nan::New<v8::String>(ErrorMessage()).ToLocalChecked());<br><br>    Local<Value> argv[argc] = {returnObject};<br>    callback<span style="color:rgb(0,102,102);font-weight:bold">-></span>Call(argc, argv);<br>}</pre></div>

</div>