<div dir="ltr">Hi all,<div><br></div><div>I'm trying to write a small tool which reads pcm16 audio from files, converts them to webm/ogg format in buffer and passes it to another program through socket (currently just dumps it on disk). I have it working with one file but when I start to encode second file the avcodec_encode_audio2 function never sets got_packet variable to 1 (see the code below). I suppose the reason is that AVFormatContext holds some state the needs to be reset before it can be used again. </div><div><br></div><div>For sake of brevity the code sample here isn't complete but should give pretty good overview about how I'm encoding audio. The my_iocontext class is just holder for AVIOContext*, internal buffer and implements write and seek functions for AVIOContext (allocated with avio_alloc_context function).</div><div><br></div><div>Any help is greatly appreciated.</div><div><br></div><div>With Regards,</div><div>Ragnar</div><div><br></div><div>//--------------------------------------------------------------</div><div><br></div><div><div>class audio_encoder </div><div>{</div><div>    AVFormatContext * formatContext;</div><div>    AVOutputFormat * outputFormat;</div><div>    AVStream * stream;</div><div>    AVCodecContext * codecContext;</div><div>    SwrContext * swr_ctx;</div><div>public:</div><div>    audio_encoder() {}</div><div>    ~audio_encoder() {</div><div>        avcodec_close(codecContext);</div><div>        swr_free(&swr_ctx);</div><div>        avformat_free_context(formatContext);</div><div>    }</div><div>    bool initialize();</div><div>    std::vector<unsigned char> encode( std::vector<unsigned char> audio );</div><div>};</div><div><br></div><div>bool audio_encoder::initialize()</div><div>{</div><div>    avformat_alloc_output_context2(&formatContext, NULL, NULL, ".webm");</div><div>    if (!formatContext) {</div><div>        return false;</div><div>    }</div><div>    </div><div>    outputFormat = formatContext->oformat;</div><div>    if ( outputFormat->audio_codec == AV_CODEC_ID_NONE ) {</div><div>        std::cout << "Audio codec not found" << std::endl;</div><div>        return false;</div><div>    }</div><div>    outputFormat->video_codec = AV_CODEC_ID_NONE;</div><div>    outputFormat->subtitle_codec = AV_CODEC_ID_NONE;</div><div>    </div><div>    AVCodec * codec = avcodec_find_encoder(outputFormat->audio_codec);</div><div>    if (!codec) {</div><div>        std::cout << "Could not find encoder for: " << avcodec_get_name(outputFormat->audio_codec) << std::endl;</div><div>        return false;</div><div>    }</div><div>    </div><div>    stream = avformat_new_stream(formatContext, codec);</div><div>    if (!stream) {</div><div>        std::cout << "Could not allocate stream" << std::endl;</div><div>        return false;</div><div>    }</div><div>    stream->id = formatContext->nb_streams-1;</div><div>    </div><div>    codecContext = stream->codec;</div><div>    codecContext->sample_fmt  = codec->sample_fmts ? codec->sample_fmts[0] : AV_SAMPLE_FMT_FLTP;</div><div>    codecContext->bit_rate    = 64000;</div><div>    codecContext->sample_rate = 16000;</div><div>    </div><div>    codecContext->channels        = av_get_channel_layout_nb_channels(codecContext->channel_layout);</div><div>    codecContext->channel_layout = AV_CH_LAYOUT_MONO;</div><div>    codecContext->channels        = av_get_channel_layout_nb_channels(codecContext->channel_layout);</div><div>    stream->time_base = av_make_q( 1, codecContext->sample_rate );</div><div><br></div><div>    if (formatContext->oformat->flags & AVFMT_GLOBALHEADER) {</div><div>        codecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;</div><div>    }</div><div><br></div><div>    int ret = avcodec_open2(codecContext, codec, nullptr );</div><div>    if (ret < 0) {</div><div>        std::cout << "Could not open audio codec: " << av_err2str(ret) << std::endl;</div><div>        return false;</div><div>    }</div><div>    </div><div>    swr_ctx = swr_alloc();</div><div>    if (!swr_ctx) {</div><div>        std::cout << "Could not allocate resampler context" << std::endl;</div><div>        return false;</div><div>    }</div><div><br></div><div>    av_opt_set_int       (swr_ctx, "in_channel_count",   codecContext->channels,       0);</div><div>    av_opt_set_int       (swr_ctx, "in_sample_rate",     codecContext->sample_rate,    0);</div><div>    av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt",      AV_SAMPLE_FMT_S16, 0);</div><div>    av_opt_set_int       (swr_ctx, "out_channel_count",  codecContext->channels,       0);</div><div>    av_opt_set_int       (swr_ctx, "out_sample_rate",    codecContext->sample_rate,    0);</div><div>    av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt",     codecContext->sample_fmt,     0);</div><div><br></div><div>    if ((ret = swr_init(swr_ctx)) < 0) {</div><div>        std::cout << "Failed to initialize the resampling context" << std::endl;</div><div>        return false;</div><div>    }</div><div>    </div><div>    return true;</div><div>}</div><div><br></div><div><br></div><div>std::vector<unsigned char> audio_encoder::encode( std::vector<unsigned char> pcm_audio )</div><div>{</div><div>    <br></div><div>    my_iocontext io_ctx; </div><div>    formatContext->pb = io_ctx.get_avio();</div><div><br></div><div>    int ret = avformat_write_header(formatContext, nullptr);</div><div>    if (ret < 0) {</div><div>        std::cout << "Error occurred when opening output file: " << av_err2str(ret) << std::endl;</div><div>        return {};</div><div>    }</div><div>    </div><div>    AVFrame * frame = av_frame_alloc();</div><div>    if (!frame) {</div><div>        std::cout << "Error allocating an audio frame" << std::endl;</div><div>        return {};</div><div>    }</div><div>    frame->format = codecContext->sample_fmt;</div><div>    frame->channel_layout = codecContext->channel_layout;</div><div>    frame->sample_rate = codecContext->sample_rate;</div><div>    frame->nb_samples = codecContext->frame_size;</div><div>    if (frame->nb_samples) {</div><div>        if (av_frame_get_buffer(frame, 0) < 0) {</div><div>            std::cout << "Error allocating an audio buffer" << std::endl;</div><div>            return {};</div><div>        }</div><div>    }</div><div><br></div><div>    int samples_count = 0;</div><div>    unsigned int size_in_bytes = (codecContext->frame_size*2);</div><div>    unsigned int cycles = (pcm_audio.size() / size_in_bytes );</div><div>    <br></div><div>    for( int x = 0; x < cycles; x++) {</div><div>        </div><div>        int start_idx = (x*size_in_bytes);</div><div>        std::vector<unsigned char> chunk( pcm_audio.begin()+start_idx,  pcm_audio.begin()+start_idx + size_in_bytes );</div><div>        </div><div>        </div><div>        int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, codecContext->sample_rate) + codecContext->frame_size,</div><div>                                        codecContext->sample_rate, codecContext->sample_rate, AV_ROUND_UP);</div><div><br></div><div>        int ret = av_frame_make_writable(frame);</div><div>        if (ret < 0) {</div><div>            break;</div><div>        }</div><div>        </div><div>        ret = swr_convert(swr_ctx, frame->data, dst_nb_samples, (const uint8_t **)&chunk, codecContext->frame_size); //in_frame->data</div><div>        if (ret < 0) {</div><div>            std::cout << "Error while converting" << std::endl;</div><div>            break;</div><div>        }</div><div>        </div><div>        frame->pts = av_rescale_q(samples_count, av_make_q( 1, codecContext->sample_rate ), codecContext->time_base);</div><div>        samples_count += dst_nb_samples;</div><div>        </div><div>        int got_packet = 0;</div><div>        AVPacket pkt = { 0 };</div><div>        av_init_packet( &pkt );</div><div>        ret = avcodec_encode_audio2(codecContext, &pkt, frame, &got_packet);</div><div>        if (ret < 0) {</div><div>            std::cout << "Error encoding audio frame: " << av_err2str(ret) << std::endl;</div><div>            break;</div><div>        }</div><div><br></div><div>        if (got_packet) {</div><div>            ret = write_frame(formatContext, &codecContext->time_base, stream, &pkt);</div><div>            if (ret < 0) {</div><div>                std::cout << "Error while writing audio frame: " << av_err2str(ret) << std::endl;</div><div>                break;</div><div>            }</div><div>        }</div><div>    }</div><div>    </div><div>    int got_packet = 0;</div><div>    do {</div><div>        AVPacket pkt = { 0 };</div><div>        av_init_packet(&pkt);</div><div>        int ret = avcodec_encode_audio2(codecContext, &pkt, nullptr, &got_packet);</div><div>        if (ret < 0) {</div><div>            std::cout << "Error encoding audio frame: " << av_err2str(ret) << std::endl;</div><div>            break;</div><div>        }</div><div><br></div><div>        if (got_packet) {</div><div>            ret = write_frame(formatContext, &codecContext->time_base, stream, &pkt);</div><div>            if (ret < 0) {</div><div>                std::cout << "Error while writing audio frame: " <<  av_err2str(ret) << std::endl;</div><div>                break;</div><div>            }</div><div>        }</div><div>    } while ( got_packet );</div><div>    </div><div>    av_write_trailer(formatContext);</div><div>    </div><div>    av_frame_free( &frame );</div><div><br></div><div>    return io_ctx.get_data();</div><div>}</div><div><br></div><div><br></div><div>int main(int argc, char **argv)</div><div>{</div><div><br></div><div>    std::ifstream input_file;</div><div>    input_file.open( "/tmp/input.wav", std::ios_base::in | std::ios_base::binary );</div><div>    if ( !input_file.is_open() ) {</div><div>        printf("Unable to open input file.\n");</div><div>        return 1;</div><div>    }</div><div>    std::vector<unsigned char> pcm_audio( ( std::istreambuf_iterator<char>( input_file ) ), ( std::istreambuf_iterator<char>() ) );</div><div>    <br></div><div>    </div><div>    av_register_all();</div><div>    av_log_set_level(AV_LOG_DEBUG);</div><div>    </div><div>    audio_encoder encoder;</div><div>    if (!encoder.initialize()) {</div><div>        std::cout << "Error initializing ..." << std::endl;</div><div>        exit(1);</div><div>    }</div><div>    </div><div>    std::vector<unsigned char> bufr = encoder.encode( pcm_audio );</div><div>    </div><div>    std::ofstream cmp( "/tmp/result.webm", std::ios_base::out | std::ios_base::binary );</div><div>    cmp.write( ( char * )&bufr[0], bufr.size() );</div><div>    cmp.close();</div><div>    </div><div>    std::vector<unsigned char> bufr2 = encoder.encode( pcm_audio );</div><div>    </div><div>    std::ofstream cmp2( "/tmp/result2.webm", std::ios_base::out | std::ios_base::binary );</div><div>    cmp2.write( ( char * )&bufr2[0], bufr2.size() );</div><div>    cmp2.close();</div><div><br></div><div>    return 0;</div><div>}</div></div><div><br></div></div>