<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <br>
    Hello libav and ffmpeg users.<br>
    <br>
    I am new with ffmpeg and I have a problem with audio transcoding.
    I've tried to implement almost <br>
    all found tutorials, but it still doesn't work correctly.<br>
    <br>
    I have an mpeg-ts container with h264 video and ac3 audio codecs.<br>
    <br>
    I need to change container from mpeg-ts to mp4 with copying video
    and change audio format from ac3 to aac or mp3.<br>
    <br>
    I've alreary changed container and copy video, but my audio stream
    has lost last few seconds of audio after transcoding<br>
    and I don't understand why.<br>
    <br>
    For example: if i try to convert 17s video i will lose 3 seconds of
    audio in the for mp3 and 5s for aac.<br>
    <br>
    If somebody have such kind of problem please give an advice what I
    did wrong. Or may be someone have a complete example of<br>
    transcoding audio fram by frame. It will be very usefull for me.<br>
    <br>
    And this is my code: <br>
    <br>
    #include <stdexcept><br>
    #include <iostream> <br>
    #include <sstream><br>
    #include <cstring><br>
    #include <cstdlib><br>
    #include <cassert><br>
    <br>
    extern "C" {<br>
    #include <libavcodec/avcodec.h><br>
    #include <libavformat/avformat.h><br>
    #include <libavutil/avutil.h><br>
    #include <libavutil/error.h><br>
    #include <libavutil/opt.h><br>
    #include <libavutil/samplefmt.h><br>
    #include <libavutil/rational.h><br>
    #include <libavutil/mathematics.h><br>
    #include <libavutil/samplefmt.h><br>
    #include <libswresample/swresample.h><br>
    <br>
    }<br>
    <br>
    void usage(char *argv[]) {<br>
        std::cout << "Changes container of media file from any
    format (mostly mpeg-ts) to mp4" << std::endl;<br>
        std::cout << "usage: " << argv[0] << " INFILE
    [OUTFILE]" << std::endl;<br>
    }<br>
    <br>
    void rescalePacket(AVPacket &pkt, int64_t startTime, AVRational
    inTimeBase, AVRational outTimeBase) {<br>
        if (pkt.pts != AV_NOPTS_VALUE) {<br>
            pkt.pts = av_rescale_q(pkt.pts - startTime, inTimeBase,
    outTimeBase);<br>
        }<br>
    <br>
        if (pkt.dts != AV_NOPTS_VALUE) {<br>
            pkt.dts = av_rescale_q(pkt.dts - startTime, inTimeBase,
    outTimeBase);<br>
        }<br>
    <br>
        if (pkt.duration > 0) {<br>
            pkt.duration = av_rescale_q(pkt.duration, inTimeBase,
    outTimeBase);<br>
        }<br>
    }<br>
    <br>
    AVFormatContext* initInputContext(const std::string& fileName) {<br>
        assert(!fileName.empty());<br>
        AVFormatContext* context = NULL;<br>
    <br>
        if (avformat_open_input(&context, fileName.c_str(), NULL,
    NULL) < 0) {<br>
            std::cout << "Unable to get AVFormatContext from "
    << fileName << std::endl;<br>
            return NULL;<br>
        }<br>
    <br>
        if (avformat_find_stream_info(context, NULL) < 0) {<br>
            std::cout << "Could not find stream information"
    << std::endl;<br>
            return NULL;<br>
        }<br>
    <br>
        return context;<br>
    }<br>
    <br>
    AVFormatContext* initOutputContext(const std::string& fileName)
    {<br>
        assert(!fileName.empty());<br>
        AVFormatContext* formatContext = NULL;<br>
    <br>
        if (avformat_alloc_output_context2(&formatContext, NULL,
    NULL, fileName.c_str()) < 0) {<br>
            if (avformat_alloc_output_context2(&formatContext, NULL,
    "mp4", NULL) < 0) {<br>
                std::cout << "Could not deduce output format: "
    << fileName << std::endl;<br>
            }<br>
        }<br>
    <br>
        if (!formatContext) {<br>
            std::cout << "Unable to init format context" <<
    std::endl;<br>
            return NULL;<br>
        }<br>
    <br>
        return formatContext;<br>
    }<br>
    <br>
    AVStream* getStream(AVFormatContext* formatContext, AVMediaType
    mediaType) {<br>
        assert(formatContext != NULL);<br>
        int index = 0;<br>
    <br>
        AVStream* stream = NULL;<br>
    <br>
        if ((index = av_find_best_stream(formatContext, mediaType, -1,
    -1, NULL, 0)) < 0) {<br>
            std::cout << "Stream index not found" <<
    std::endl;<br>
            return NULL;<br>
        }<br>
    <br>
        stream = formatContext->streams[index];<br>
    <br>
        if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) {<br>
            AVCodec* decoder =
    avcodec_find_decoder(stream->codec->codec_id);<br>
    <br>
            if (!decoder) {<br>
                std::cout << "Could not find stream decoder with
    ID: " << stream->codec->codec_id << std::endl;<br>
            } else if (avcodec_open2(stream->codec, decoder, NULL)
    < 0) {<br>
                std::cout << "Could not open codec: " <<
    stream->codec->codec_id << std::endl;<br>
            }<br>
        }<br>
    <br>
        return stream;<br>
    }<br>
    <br>
    SwrContext* swrContext = NULL;<br>
    uint8_t* rawData = NULL;<br>
    int rawDataSize = 0;<br>
    <br>
    bool initEncoder(AVFormatContext* context, AVStream* inStream,
    AVStream* outStream, CodecID codecId) {<br>
        swrContext = swr_alloc_set_opts(NULL,
    outStream->codec->channel_layout,
    outStream->codec->sample_fmt,
    outStream->codec->sample_rate,
    inStream->codec->channel_layout,
    inStream->codec->sample_fmt,
    inStream->codec->sample_rate, 0, NULL);<br>
    <br>
        if (!swrContext) {<br>
            return false;<br>
        }<br>
    <br>
        if (swr_init(swrContext) < 0) {<br>
           return false;<br>
        }<br>
    <br>
        if (av_samples_alloc(&rawData, &rawDataSize,
    outStream->codec->channels,
    outStream->codec->frame_size,
    outStream->codec->sample_fmt, 1) < 0) {<br>
            return false;<br>
        }<br>
    <br>
        return true;<br>
    }<br>
    <br>
    AVStream* createStream(AVFormatContext* formatContext, CodecID
    codecId, AVStream* inStream = NULL) {<br>
        AVCodec* encoder = avcodec_find_encoder(codecId);<br>
    <br>
        if (!encoder) {<br>
            std::cout << "Could not find stream encoder with ID: "
    << codecId;<br>
            return NULL;<br>
        }<br>
    <br>
        AVStream* stream = avformat_new_stream(formatContext, encoder);<br>
    <br>
        if (!stream) {<br>
            std::cout << "Could not create output stream" <<
    std::endl;<br>
            return NULL;<br>
        }<br>
    <br>
        if (inStream && stream->codec->codec_type ==
    AVMEDIA_TYPE_AUDIO) {<br>
            stream->id = 1;<br>
            stream->codec->bit_rate = 192000;<br>
            stream->codec->sample_rate = 44100;<br>
            stream->codec->sample_fmt = AV_SAMPLE_FMT_FLT;<br>
            stream->codec->channel_layout = AV_CH_LAYOUT_STEREO;<br>
            stream->codec->channels =
    av_get_channel_layout_nb_channels(stream->codec->channel_layout);<br>
            stream->r_frame_rate = inStream->r_frame_rate;<br>
            stream->avg_frame_rate = inStream->avg_frame_rate;<br>
            stream->duration = inStream->duration;<br>
    <br>
            AVDictionary *options = NULL;<br>
            av_dict_set(&options, "strict", "experimental", 0);<br>
    <br>
            if (avcodec_open2(stream->codec, encoder, &options)
    < 0) {<br>
                std::cout << "Could not open codec: " <<
    stream->codec->codec_id << std::endl;<br>
            }<br>
        }<br>
    <br>
        return stream;<br>
    }<br>
    <br>
    bool copyStreamContext(AVStream* outStream, AVStream* inStream) {<br>
        if (avcodec_copy_context(outStream->codec,
    inStream->codec) < 0) {<br>
            std::cout << "Could not copy codec context" <<
    std::endl;<br>
            return false;<br>
        }<br>
    <br>
        outStream->codec->codec_tag = 0;<br>
        outStream->codec->time_base = outStream->time_base;<br>
        outStream->sample_aspect_ratio =
    outStream->codec->sample_aspect_ratio;<br>
        outStream->r_frame_rate = inStream->r_frame_rate;<br>
        outStream->avg_frame_rate = inStream->avg_frame_rate;<br>
        outStream->duration = inStream->duration;<br>
        av_dict_copy(&outStream->metadata, inStream->metadata,
    0);<br>
    <br>
        return true;<br>
    }<br>
    <br>
    int ra = 0;<br>
    int wa = 0;<br>
    int rv = 0;<br>
    int wv = 0;<br>
    <br>
    <b>int decodeFromPacket(AVCodecContext* codecContext, AVPacket*
      packet, AVFrame*& frame) {</b><b><br>
    </b><b>    if (!frame) {</b><b><br>
    </b><b>        frame = avcodec_alloc_frame();</b><b><br>
    </b><b>    }</b><b><br>
    </b><b><br>
    </b><b>    avcodec_get_frame_defaults(frame);</b><b><br>
    </b><b><br>
    </b><b>    int gotFrame = 0;</b><b><br>
    </b><b>    int result = avcodec_decode_audio4(codecContext, frame,
      &gotFrame, packet);</b><b><br>
    </b><b><br>
    </b><b>    if (result < 0) {</b><b><br>
    </b><b>        std::cout << "Could not decode audio frame"
      << std::endl;</b><b><br>
    </b><b>        packet->size = 0;</b><b><br>
    </b><b>        packet->data = NULL;</b><b><br>
    </b><b><br>
    </b><b>        return 0;</b><b><br>
    </b><b>    }</b><b><br>
    </b><b><br>
    </b><b>    packet->size -= result;</b><b><br>
    </b><b>    packet->data += result;</b><b><br>
    </b><b><br>
    </b><b>    return gotFrame;</b><b><br>
    </b><b>}</b><b><br>
    </b><b><br>
    </b><b>int convertFrame(AVCodecContext* codecContext, AVFrame*&
      frame) {</b><b><br>
    </b><b>    int result = swr_convert(swrContext, &rawData,
      codecContext->frame_size, (const
      uint8_t**)frame->extended_data, frame->nb_samples);</b><b><br>
    </b><b><br>
    </b><b>    if (result < 0) {</b><b><br>
    </b><b>        std::cout << "Could not convert frame content:
      " << std::endl;</b><b><br>
    </b><b>        return 0;</b><b><br>
    </b><b>    }</b><b><br>
    </b><b><br>
    </b><b>    avcodec_get_frame_defaults(frame);</b><b><br>
    </b><b>    frame->nb_samples = codecContext->frame_size;</b><b><br>
    </b><b>    frame->format     = codecContext->sample_fmt;</b><b><br>
    </b><b><br>
    </b><b>    result = avcodec_fill_audio_frame(frame,
      codecContext->channels, codecContext->sample_fmt, (uint8_t
      *)rawData, rawDataSize, 1);</b><b><br>
    </b><b><br>
    </b><b>    if (result < 0) {</b><b><br>
    </b><b>        std::cout << "Could not fill output frame"
      << std::endl;</b><b><br>
    </b><b>        return 0;</b><b><br>
    </b><b>    }</b><b><br>
    </b><b><br>
    </b><b>    return 1;</b><b><br>
    </b><b>}</b><b><br>
    </b><b><br>
    </b><b>int encodeToPacket(AVCodecContext* codecContext, AVPacket*
      packet, AVFrame*& frame) {</b><b><br>
    </b><b>    int gotPacket = 0;</b><b><br>
    </b><b><br>
    </b><b>    int result = avcodec_encode_audio2(codecContext, packet,
      frame, &gotPacket);</b><b><br>
    </b><b><br>
    </b><b>    if (result < 0) {</b><b><br>
    </b><b>        std::cout << "Could not encode audio frame"
      << std::endl;</b><b><br>
    </b><b>        return 0;</b><b><br>
    </b><b>    }</b><b><br>
    </b><b><br>
    </b><b>    return gotPacket;</b><b><br>
    </b><b>}</b><b><br>
    </b><b><br>
    </b><b>void writeFrame (AVFormatContext* formatContext, AVPacket*
      packet, int streamIndex) {</b><b><br>
    </b><b>    packet->stream_index = streamIndex;</b><b><br>
    </b><b><br>
    </b><b>    if (av_interleaved_write_frame(formatContext, packet)
      < 0) {</b><b><br>
    </b><b>        std::cout << "Could not write audio frame"
      << std::endl;</b><b><br>
    </b><b>    }</b><b><br>
    </b><b><br>
    </b><b>    if (streamIndex == 1) {</b><b><br>
    </b><b>        wa++;</b><b><br>
    </b><b>    } else {</b><b><br>
    </b><b>        wv++;</b><b><br>
    </b><b>    }</b><b><br>
    </b><b>}</b><br>
    <br>
    int64_t time_base = 0;<br>
    <br>
    <b>void transcodeAudioPacket(AVFormatContext* formatContext,
      AVStream* inStream, AVStream* outStream, AVPacket* inPacket,
      AVFrame*& frame) {</b><b><br>
    </b><b>    int result = 0;</b><b><br>
    </b><b><br>
    </b><b>    while(inPacket->size > 0) {</b><b><br>
    </b><b>        result = decodeFromPacket(inStream->codec,
      inPacket, frame);</b><b><br>
    </b><b><br>
    </b><b>        if (!result) {</b><b><br>
    </b><b>            continue;</b><b><br>
    </b><b>        }</b><b><br>
    </b><b><br>
    </b><b>        result = convertFrame(outStream->codec, frame);</b><b><br>
    </b><b><br>
    </b><b>        if (!result) {</b><b><br>
    </b><b>            continue;</b><b><br>
    </b><b>        }</b><b><br>
    </b><b><br>
    </b><b>        AVPacket outPacket = {0};</b><b><br>
    </b><b>        av_init_packet(&outPacket);</b><b><br>
    </b><b><br>
    </b><b>        result = encodeToPacket(outStream->codec,
      &outPacket, frame);</b><b><br>
    </b><b><br>
    </b><b>        if (result) {</b><b><br>
    </b><b>            writeFrame(formatContext,&outPacket,
      outStream->index);</b><b><br>
    </b><b>        }</b><b><br>
    </b><b><br>
    </b><b>        av_free_packet(&outPacket);</b><b><br>
    </b><b>    }</b><b><br>
    </b><b>}</b><br>
    <br>
    void processVideo(const std::string& inputFile, const
    std::string& outputFile) {<br>
        AVFormatContext* inFormatContext  = initInputContext(inputFile);<br>
        AVFormatContext* outFormatContext =
    initOutputContext(outputFile);<br>
    <br>
        outFormatContext->duration   = inFormatContext->duration;<br>
        outFormatContext->bit_rate   = inFormatContext->bit_rate;<br>
        outFormatContext->start_time =
    inFormatContext->start_time;<br>
    <br>
        AVStream* inVideoStream = getStream(inFormatContext,
    AVMEDIA_TYPE_VIDEO);<br>
        AVStream* inAudioStream = getStream(inFormatContext,
    AVMEDIA_TYPE_AUDIO);<br>
    <br>
        AVOutputFormat* outFormat = outFormatContext->oformat;<br>
        outFormat->codec_tag   = NULL;<br>
    <br>
        AVStream* outVideoStream = createStream(outFormatContext,
    outFormat->video_codec);<br>
        AVStream* outAudioStream = createStream(outFormatContext,
    outFormat->audio_codec, inAudioStream);<br>
    <br>
        copyStreamContext(outVideoStream, inVideoStream);<br>
        av_dict_copy(&outAudioStream->metadata,
    inAudioStream->metadata, 0);<br>
    <br>
        initEncoder(outFormatContext, inAudioStream, outAudioStream,
    outFormat->audio_codec);<br>
    <br>
        if (!(outFormat->flags & AVFMT_NOFILE)) {<br>
             if (avio_open(&outFormatContext->pb,
    outputFile.c_str(), AVIO_FLAG_WRITE) < 0) {<br>
                 std::cout << "Could not open output file: "
    << outputFile << std::endl;<br>
                 return;<br>
             }<br>
        }<br>
    <br>
        if (outFormat->flags & AVFMT_GLOBALHEADER) {<br>
            outVideoStream->codec->flags |=
    CODEC_FLAG_GLOBAL_HEADER;<br>
            outAudioStream->codec->flags |=
    CODEC_FLAG_GLOBAL_HEADER;<br>
        }<br>
    <br>
        av_dump_format(inFormatContext, 0, inputFile.c_str(), 0);<br>
        av_dump_format(outFormatContext, 0, outputFile.c_str(), 1);<br>
    <br>
        AVDictionary* options = NULL;<br>
        av_dict_set(&options, "movflags", "frag_keyframe", 0);<br>
    <br>
        if (avformat_write_header(outFormatContext, &options) <
    0) {<br>
            std::cout << "Unable to write headers " <<
    std::endl;<br>
        }<br>
    <br>
        av_dict_free(&options);<br>
    <br>
        AVPacket packet  = {0};<br>
        AVFrame* frame = avcodec_alloc_frame();<br>
        int result    = 0;<br>
        int gotPacket = 0;<br>
    <br>
       <b> // rewrite video and audio packets</b><b><br>
    </b><b>    while (av_read_frame(inFormatContext, &packet) >=
      0) {</b><b><br>
    </b><b>        if (packet.stream_index == outAudioStream->index)
      {</b><b><br>
    </b><b>            ra++;</b><b><br>
    </b><b>            //rescalePacket(packet,
      inFormatContext->start_time, inAudioStream->time_base,
      outAudioStream->time_base);</b><b><br>
    </b><b>            transcodeAudioPacket(outFormatContext,
      inAudioStream, outAudioStream, &packet, frame);</b><b><br>
    </b><b>        } else if (packet.stream_index ==
      outVideoStream->index) {</b><b><br>
    </b><b>            rv++;</b><b><br>
    </b><b>            //rescalePacket(packet,
      inFormatContext->start_time, inVideoStream->time_base,
      outVideoStream->time_base);</b><b><br>
    </b><b>            writeFrame(outFormatContext, &packet,
      outVideoStream->index);</b><b><br>
    </b><b>        }</b><b><br>
    </b><b><br>
    </b><b>        av_free_packet(&packet);</b><b><br>
    </b><b>    }</b><b><br>
    </b><br>
        gotPacket = 1;<br>
    <br>
        std::cout << "Video => read = " << rv << ";
    wrote = " << wv << std::endl;<br>
        std::cout << "Audio => read = " << ra << ";
    wrote = " << wa << std::endl;<br>
    <br>
        packet.size = 0;<br>
        packet.data = NULL;<br>
    <br>
        while (gotPacket) {<br>
            result = avcodec_encode_audio2(outAudioStream->codec,
    &packet, NULL, &gotPacket);<br>
    <br>
            if (result >= 0 && gotPacket) {<br>
                packet.stream_index = outAudioStream->index;<br>
    <br>
                if (av_interleaved_write_frame(outFormatContext,
    &packet) < 0) {<br>
                    std::cout << "Could not write audio frame"
    << std::endl;<br>
                } else {<br>
                    wa++;<br>
                }<br>
            } else {<br>
                std::cout << "Could not encode audio frame"
    << std::endl;<br>
            }<br>
    <br>
            av_free_packet(&packet);<br>
        }<br>
    <br>
        std::cout << "Video => read = " << rv << ";
    wrote = " << wv << std::endl;<br>
        std::cout << "Audio => read = " << ra << ";
    wrote = " << wa << std::endl;<br>
    <br>
        av_free(frame);<br>
        av_free(rawData);<br>
        swr_free(&swrContext);<br>
    <br>
        if (av_write_trailer(outFormatContext) < 0) {<br>
            std::cout << "Unable to write trailer" <<
    std::endl;<br>
            return;<br>
        }<br>
    <br>
        avcodec_close(inAudioStream->codec);<br>
        avcodec_close(outAudioStream->codec);<br>
    <br>
        // close input<br>
        avformat_close_input(&inFormatContext);<br>
        inFormatContext = NULL;<br>
    <br>
        // close output<br>
        if (!(outFormat->flags & AVFMT_NOFILE)) {<br>
            avio_close(outFormatContext->pb);<br>
        }<br>
    <br>
        avformat_free_context(outFormatContext);<br>
        outFormatContext = NULL;<br>
    }<br>
    <br>
    int main(int argc, char *argv[]) {<br>
        std::string inpFile, outFile;<br>
    <br>
        if (argc < 2) {<br>
            std::cout << "error: you should specify input file for
    transcoding" << std::endl;<br>
            usage(argv);<br>
            return 1;<br>
        }<br>
    <br>
        inpFile = argv[1];<br>
        if (argc == 3) {<br>
           outFile = argv[2];<br>
        } else {<br>
           outFile = "out.mp4";<br>
        } <br>
    <br>
        // register all muxers and demuxers<br>
        avcodec_register_all();<br>
        av_register_all();<br>
    <br>
        processVideo(inpFile, outFile);<br>
    <br>
        return 0;<br>
    }<br>
    <br>
  </body>
</html>