[Libav-user] Remuxing/Codec copy over rtp_mpegts really bad quality result

Benji Amello benji.amello at gmail.com
Tue Dec 26 03:13:00 EET 2017


Hi,

I am struggling with issue for past 2 weeks & making almost no progress.
I am trying to do codec copy of a stream(testing with file & later
going to use live stream) with format rtp_mpegts over network & play
using VLC player. Started my proof of concept code with slightly
modified remuxing.c in the examples.


I am essentially trying to do is to replicate
./ffmpeg -re -i TEST_VIDEO.ts  -acodec copy -vcodec copy -f rtp_mpegts
rtp://239.245.0.2:5002

Streaming is happening, but the quality is terrible.
Looks like many frames are skipped plus streaming is happening really
slow(buffer underflow reported by VLC player)

File plays perfectly fine directly on VLC player.
Please help.

Stream details.
Input #0, mpegts, from ' TEST_VIDEO.ts':
  Duration: 00:10:00.40, start: 41313.400811, bitrate: 2840 kb/s
  Program 1
    Stream #0:0[0x11]: Video: h264 (High) ([27][0][0][0] / 0x001B),
yuv420p(tv, bt709, top first), 1440x1080 [SAR 4:3 DAR 16:9], 29.97
fps, 59.94 tbr, 90k tbn, 59.94 tbc
    Stream #0:1[0x14]: Audio: ac3 (AC-3 / 0x332D4341), 48000 Hz,
stereo, fltp, 448 kb/s
Output #0, rtp_mpegts, to 'rtp://239.255.0.2:5004':
  Metadata:
    encoder         : Lavf57.83.100
    Stream #0:0: Video: h264 (High) ([27][0][0][0] / 0x001B),
yuv420p(tv, bt709, top first), 1440x1080 [SAR 4:3 DAR 16:9], q=2-31,
29.97 fps, 59.94 tbr, 90k tbn, 29.97 tbc
    Stream #0:1: Audio: ac3 (AC-3 / 0x332D4341), 48000 Hz, stereo,
fltp, 448 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (copy)
  Stream #0:1 -> #0:1 (copy)
Press [q] to stop, [?] for help
frame=  418 fps=5.2 q=-1.0 size=    3346kB time=00:00:08.50
bitrate=3223.5kbits/s speed=0.106x
Thanks
Benji


My complete source code(This is almost same as remuxing.c)


#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>

static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket
*pkt, const char *tag)
{
    AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;

    printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s
duration_time:%s stream_index:%d\n",
           tag,
           av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
           av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
           av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
           pkt->stream_index);
}


int main(int argc, char **argv)
{
    AVOutputFormat *ofmt = NULL;
    AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
    AVPacket pkt;
    const char *in_filename, *out_filename;
    int ret, i;
    int stream_index = 0;
    int *stream_mapping = NULL;
    int stream_mapping_size = 0;
    AVRational mux_timebase;
    int64_t start_time = 0; //(of->start_time == AV_NOPTS_VALUE) ? 0 :
of->start_time;
    int64_t ost_tb_start_time = 0; //av_rescale_q(start_time,
AV_TIME_BASE_Q, ost->mux_timebase);

    if (argc < 3) {
        printf("usage: %s input output\n"
               "API example program to remux a media file with
libavformat and libavcodec.\n"
               "The output format is guessed according to the file extension.\n"
               "\n", argv[0]);
        return 1;
    }

    in_filename  = argv[1];
    out_filename = argv[2];

    av_register_all();
    avcodec_register_all();
    avformat_network_init();

    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
        fprintf(stderr, "Could not open input file '%s'", in_filename);
        goto end;
    }

    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
        fprintf(stderr, "Failed to retrieve input stream information");
        goto end;
    }

    av_dump_format(ifmt_ctx, 0, in_filename, 0);

    avformat_alloc_output_context2(&ofmt_ctx, NULL, "rtp_mpegts", out_filename);
    if (!ofmt_ctx) {
        fprintf(stderr, "Could not create output context\n");
        ret = AVERROR_UNKNOWN;
        goto end;
    }

    stream_mapping_size = ifmt_ctx->nb_streams;
    stream_mapping = av_mallocz_array(stream_mapping_size,
sizeof(*stream_mapping));
    if (!stream_mapping) {
        ret = AVERROR(ENOMEM);
        goto end;
    }

    ofmt = ofmt_ctx->oformat;

    for (i = 0; i < ifmt_ctx->nb_streams; i++)
    {
        AVStream *out_stream;
        AVStream *in_stream = ifmt_ctx->streams[i];
        AVCodecParameters *in_codecpar = in_stream->codecpar;

        if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
            in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
            in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
            stream_mapping[i] = -1;
            continue;
        }

        stream_mapping[i] = stream_index++;


        out_stream = avformat_new_stream(ofmt_ctx, NULL);
        if (!out_stream) {
            fprintf(stderr, "Failed allocating output stream\n");
            ret = AVERROR_UNKNOWN;
            goto end;
        }

        //out_stream->codecpar->codec_tag = 0;
        if (0 == out_stream->codecpar->codec_tag)
        {
            unsigned int codec_tag_tmp;

            if (!out_stream->codecpar->codec_tag ||
                av_codec_get_id (ofmt->codec_tag,
in_codecpar->codec_tag) == in_codecpar->codec_id ||
                !av_codec_get_tag2(ofmt->codec_tag,
in_codecpar->codec_id, &codec_tag_tmp))
                out_stream->codecpar->codec_tag  = in_codecpar->codec_tag;
        }
        //ret = avcodec_parameters_to_context(ost->enc_ctx, ist->st->codecpar);

        ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
        if (ret < 0) {
            fprintf(stderr, "Failed to copy codec parameters\n");
            goto end;
        }
        //out_stream->codecpar->codec_tag = codec_tag;
        // copy timebase while removing common factors

        printf("bit_rate %lld sample_rate %d frame_size %d\n",
               in_codecpar->bit_rate, in_codecpar->sample_rate,
in_codecpar->frame_size);

        out_stream->avg_frame_rate = in_stream->avg_frame_rate;

        ret = avformat_transfer_internal_stream_timing_info(ofmt,

out_stream, in_stream,
                                                            AVFMT_TBCF_AUTO);
        if (ret < 0) {
            fprintf(stderr,
"avformat_transfer_internal_stream_timing_info failed\n");
            goto end;
        }

        if (out_stream->time_base.num <= 0 || out_stream->time_base.den <= 0)
            out_stream->time_base =
av_add_q(av_stream_get_codec_timebase(out_stream), (AVRational){0,
1});

        // copy estimated duration as a hint to the muxer
        if (out_stream->duration <= 0 && in_stream->duration > 0)
            out_stream->duration = av_rescale_q(in_stream->duration,
in_stream->time_base, out_stream->time_base);

        // copy disposition
        out_stream->disposition = in_stream->disposition;

        out_stream->sample_aspect_ratio = in_stream->sample_aspect_ratio;
        out_stream->avg_frame_rate = in_stream->avg_frame_rate;
        out_stream->r_frame_rate = in_stream->r_frame_rate;

        if ( in_codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {

            mux_timebase = in_stream->time_base;
        }


        if (in_stream->nb_side_data) {
            for (i = 0; i < in_stream->nb_side_data; i++) {
                const AVPacketSideData *sd_src = &in_stream->side_data[i];
                uint8_t *dst_data;

                dst_data = av_stream_new_side_data(out_stream,
sd_src->type, sd_src->size);
                if (!dst_data)
                    return AVERROR(ENOMEM);
                memcpy(dst_data, sd_src->data, sd_src->size);
            }
        }
    }

    av_dump_format(ofmt_ctx, 0, out_filename, 1);

    start_time = ofmt_ctx->duration;
    ost_tb_start_time = av_rescale_q(ofmt_ctx->duration,
AV_TIME_BASE_Q, mux_timebase);

    if (!(ofmt->flags & AVFMT_NOFILE))
    {
        ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
        if (ret < 0) {
            fprintf(stderr, "Could not open output file '%s'", out_filename);
            goto end;
        }
    }

    ret = avformat_write_header(ofmt_ctx, NULL);
    if (ret < 0) {
        fprintf(stderr, "Error occurred when opening output file\n");
        goto end;
    }

    while (1)
    {
        AVStream *in_stream, *out_stream;

        ret = av_read_frame(ifmt_ctx, &pkt);
        if (ret < 0)
            break;

        in_stream  = ifmt_ctx->streams[pkt.stream_index];
        if (pkt.stream_index >= stream_mapping_size ||
            stream_mapping[pkt.stream_index] < 0) {
            av_packet_unref(&pkt);
            continue;
        }

        pkt.stream_index = stream_mapping[pkt.stream_index];
        out_stream = ofmt_ctx->streams[pkt.stream_index];

        //log_packet(ifmt_ctx, &pkt, "in");


        //ofmt_ctx->bit_rate = ifmt_ctx->bit_rate;
        ofmt_ctx->duration = ifmt_ctx->duration;
        /* copy packet */
        //pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base,
out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
        //pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base,
out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);

        if (pkt.pts != AV_NOPTS_VALUE)
            pkt.pts = av_rescale_q(pkt.pts,
in_stream->time_base,mux_timebase) - ost_tb_start_time;
        else
            pkt.pts = AV_NOPTS_VALUE;

        if (pkt.dts == AV_NOPTS_VALUE)
            pkt.dts = av_rescale_q(pkt.dts, AV_TIME_BASE_Q, mux_timebase);
        else
            pkt.dts = av_rescale_q(pkt.dts, in_stream->time_base, mux_timebase);
        pkt.dts -= ost_tb_start_time;

        pkt.duration = av_rescale_q(pkt.duration,
in_stream->time_base, mux_timebase);
        //pkt.duration = av_rescale_q(1,
av_inv_q(out_stream->avg_frame_rate), mux_timebase);
        pkt.pos = -1;
        //log_packet(ofmt_ctx, &pkt, "out");


        ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
        if (ret < 0) {
            fprintf(stderr, "Error muxing packet\n");
            break;
        }
        av_packet_unref(&pkt);
    }

    av_write_trailer(ofmt_ctx);
end:

    avformat_close_input(&ifmt_ctx);

    /* close output */
    if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
        avio_closep(&ofmt_ctx->pb);
    avformat_free_context(ofmt_ctx);

    av_freep(&stream_mapping);

    if (ret < 0 && ret != AVERROR_EOF) {
        fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
        return 1;
    }

    return 0;
}


More information about the Libav-user mailing list