/*
上面例子，要求更改：读取完输入Mp4文件后，能够反复循环读取输出
要使程序在读取完输入文件后反复循环输出，请在处理AVPacket的部分中添加一个外部循环。以下是修改后的程序：
现在，这个程序将在结束输入文件后返回到开始并继续播放。为了终止流程，您需要使用中断（如CTRL+C）手动停止程序。
*/

#include <iostream>
#include <thread>
#include <chrono>
#include <cstdio>

extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/time.h>
}

// Load the next packet from the input format context, return whether a packet was loaded
// If the end of file is reached, it will seek to the beginning to loop the input
char load_packet(AVFormatContext *inputFormatContext, AVPacket *pkt)
{
    if (av_read_frame(inputFormatContext, pkt) >= 0)
    {
        return 1;
    }

    // Seek to the beginning and try reading again
    av_seek_frame(inputFormatContext, -1, 0, AVSEEK_FLAG_BACKWARD);
    return av_read_frame(inputFormatContext, pkt) >= 0;
}

int main(int argc, char *argv[])
{
    if (argc != 4)
    {
        std::cerr << "Usage: " << argv[0] <<"<input.mp4> <host> <port>"<< std::endl;
        return 1;
    }

    const char *inputFilename = argv[1];
    const char *host = argv[2];
    int port = std::stoi(argv[3]);

    av_register_all();
    avformat_network_init();

    AVFormatContext *inputFormatContext = nullptr;
    if (avformat_open_input(&inputFormatContext, inputFilename, nullptr, nullptr) < 0)
    {
        std::cerr << "Could not open input file: " << inputFilename << std::endl;
        return 2;
    }

    if (avformat_find_stream_info(inputFormatContext, nullptr) < 0)
    {
        std::cerr << "Could not find stream info" << std::endl;
        return 3;
    }

    av_dump_format(inputFormatContext, 0, inputFilename, 0);

    int videoStreamIndex = -1;
    int audioStreamIndex = -1;

    for (unsigned int i = 0; i < inputFormatContext->nb_streams; i++)
    {
        if (inputFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoStreamIndex = i;
        }
        else if (inputFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audioStreamIndex = i;
        }
    }

    if (videoStreamIndex == -1 || audioStreamIndex == -1)
    {
        std::cerr << "Could not find video and/or audio stream" << std::endl;
        return 4;
    }

    // Set up output.
    AVFormatContext *outputFormatContext = nullptr;
    if (avformat_alloc_output_context2(&outputFormatContext, nullptr, "rtp", nullptr) < 0)
    {
        std::cerr << "Could not allocate output context" << std::endl;
        return 5;
    }

    for (int i = 0; i < inputFormatContext->nb_streams; i++)
    {
        AVStream *inputStream = inputFormatContext->streams[i];
        AVStream *outputStream = avformat_new_stream(outputFormatContext, nullptr);
        if (!outputStream) {
            std::cerr << "Could not allocate stream" << std::endl;
            return 6;
        }

        avcodec_parameters_copy(outputStream->codecpar, inputStream->codecpar);
        if (i == videoStreamIndex)
        {
            outputStream->codecpar->codec_tag = MKTAG('H','2','6','4');
        }
        else if (i == audioStreamIndex)
        {
            outputStream->codecpar->codec_tag = MKTAG('A','A','C',' ');
        }
    }

    av_dump_format(outputFormatContext, 0, host, 1);

    AVDictionary *outputOptions = nullptr;
    av_dict_set_int(&outputOptions, "ttl", 64, 0);
    av_dict_set_int(&outputOptions, "localport", 8000, 0);

    std::string outputUri = "rtp://" + std::string(host) + ":" + std::to_string(port);
    if (avio_open2(&outputFormatContext->pb, outputUri.c_str(), AVIO_FLAG_WRITE, nullptr, &outputOptions) < 0)
    {
        std::cerr << "Could not open output" << std::endl;
        return 7;
    }

    if (avformat_write_header(outputFormatContext, nullptr) < 0)
    {
        std::cerr <<"Could not write header"<< std::endl;
        return 8;
    }

    // Start streaming.
    AVPacket packet;
    av_init_packet(&packet);
    int64_t lastVideoPts = 0;
    int64_t lastAudioPts = 0;

    while (load_packet(inputFormatContext, &packet))
    {
        int streamIndex = packet.stream_index;
        AVRational timeBase = inputFormatContext->streams[streamIndex]->time_base;

        if (streamIndex == videoStreamIndex || streamIndex == audioStreamIndex)
        {
            AVPacket outputPacket;
            av_init_packet(&outputPacket);
            av_packet_ref(&outputPacket, &packet);

            av_packet_rescale_ts(&packet, timeBase, outputFormatContext->streams[streamIndex]->time_base);
            av_write_frame(outputFormatContext, &outputPacket);
            av_packet_unref(&outputPacket);

            // Sleep for synchronization.
            std::this_thread::sleep_until(std::chrono::system_clock::now() + std::chrono::duration<int64_t, std::micro>(av_rescale_q(packet.pts - (streamIndex == videoStreamIndex ? lastVideoPts : lastAudioPts), timeBase, {1, 1000000})));
            if (streamIndex == videoStreamIndex)
            {
                lastVideoPts = packet.pts;
            }
            else
            {
                lastAudioPts = packet.pts;
            }
        }

        av_packet_unref(&packet);
    }

    av_write_trailer(outputFormatContext);
    avio_closep(&outputFormatContext->pb);

    // Cleaning up.
    avformat_free_context(outputFormatContext);
    avformat_close_input(&inputFormatContext);

    return 0;
}

该程序报错：
[rtp @ 0x56332d7fb080] Only one stream supported in the RTP muxer
1.要求音视频都往同一个端口推流；2.请修复