Re-encode Audio and Video Streams

This topic describes how to use the TTranscoder class to re-encode audio and video streams.

The code snippets in this article are from the re-encode sample.

Why Re-encode?

For performance reasons AVBlocks avoids re-encoding when possible, for example when you scale a video clip, the audio will be copied to the output unchanged. Another example is when you want to resample the audio part without changing the video.

However there are some cases when you will want to force re-encoding of audio or video streams, for example, to fix errors introduced by a prior encoding.

Code

To re-encode audio and video streams, configure the TTranscoder outputs to be exactly the same as the inputs, and set the Param::ReEncode parameter on the output audio and the output video pins to Use::On, like this:

TMediaPin pin;
pin.addParam(Param::ReEncode, Use::On);

Complete C++ code

bool reEncode(const Options& opt)
{
    std::println("Input file: {}", opt.inputFile);
    std::println("Output file: {}", opt.outputFile);
    std::println("Re-encode audio forced: {}", opt.reEncodeAudio.val ? "yes" : "no");
    std::println("Re-encode video forced: {}", opt.reEncodeVideo.val ? "yes" : "no");

    deleteFile(opt.outputFile.c_str());

    try {
        // Probe input
        TMediaInfo mediaInfo;
        mediaInfo.inputs(0).file(opt.inputFile);
        mediaInfo.open();

        TTranscoder transcoder;
        transcoder.allowDemoMode(true);

        // Add input from probe
        transcoder.addInput(TMediaSocket(mediaInfo));

        // Build output socket — same container type as input
        TMediaSocket outputSocket;
        outputSocket
            .streamType(transcoder.inputs(0).streamType())
            .file(opt.outputFile);

        // Mirror all input pins to output, optionally forcing re-encode
        auto inSocket = transcoder.inputs(0);
        for (int i = 0; i < inSocket.pins().count(); ++i)
        {
            auto inPin = inSocket.pins(i);
            auto si    = inPin.streamInfo();

            TMediaPin outPin;

            if (si.mediaType() == MediaType::Video)
            {
                outPin.streamInfo(inPin.videoStreamInfo());
                if (opt.reEncodeVideo.val)
                    outPin.addParam(Param::ReEncode, Use::On);
            }
            else if (si.mediaType() == MediaType::Audio)
            {
                outPin.streamInfo(inPin.audioStreamInfo());
                if (opt.reEncodeAudio.val)
                    outPin.addParam(Param::ReEncode, Use::On);
            }

            outputSocket.addPin(std::move(outPin));
        }

        transcoder.addOutput(outputSocket);
        transcoder.open().run().close();

        return true;

    } catch (const TAVBlocksException& ex) {
        std::println(stderr, "AVBlocks error: {}", ex.what());
        return false;
    } catch (const std::exception& ex) {
        std::println(stderr, "Error: {}", ex.what());
        return false;
    }
}