Обработка видеопотока как воспроизведения с паузой - PullRequest
0 голосов
/ 21 января 2020

Я работаю над приложением, которое передает несколько видеопотоков h264 на видеостену. Я использую libav / ffmpeg libs для потоковой передачи нескольких видеофайлов одновременно из приложения. Приложение будет управлять скоростью воспроизведения, поиском, приостановкой, возобновлением, остановкой, а видеостена будет принимать только потоки udp.

Я хочу реализовать потоковую передачу так, чтобы при приостановке видео отправлялся один и тот же кадр. постоянно, чтобы он выглядел так, как будто это видеоокно в состоянии паузы.

Как я могу вставить копии того же кадра h264 в поток, чтобы он не мешал отправке более поздних кадров?

Мой код является почти точным портом transcoding.c от ffmpeg.exe. Планирование сохранения копии последнего кадра / пакета и приостановка отправки. Это может нормально работать, или я должен подойти к этому по-другому.

while (true)
{
    if (paused) {
        // USE LAST PACKET
    }
    else 
    {
        if ((ret = ffmpeg.av_read_frame(ifmt_ctx, &packet)) < 0)
            break;
    }
    stream_index = packet.stream_index;

    type = ifmt_ctx->streams[packet.stream_index]->codec->codec_type;
    Console.WriteLine("Demuxer gave frame of stream_index " + stream_index);
    if (filter_ctx[stream_index].filter_graph != null)
    {
        Console.WriteLine("Going to reencode&filter the frame\n");
        frame = ffmpeg.av_frame_alloc();
        if (frame == null)
        {
            ret = ffmpeg.AVERROR(ffmpeg.ENOMEM);
            break;
        }

        packet.dts = ffmpeg.av_rescale_q_rnd(packet.dts,
                ifmt_ctx->streams[stream_index]->time_base,
                ifmt_ctx->streams[stream_index]->codec->time_base,
                AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);
        packet.pts = ffmpeg.av_rescale_q_rnd(packet.pts,
                ifmt_ctx->streams[stream_index]->time_base,
                ifmt_ctx->streams[stream_index]->codec->time_base,
                AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);



        if (type == AVMediaType.AVMEDIA_TYPE_VIDEO)
        {

            ret = ffmpeg.avcodec_decode_video2(stream_ctx[packet.stream_index].dec_ctx, frame,
                &got_frame, &packet); 

        }
        else
        {
            ret = ffmpeg.avcodec_decode_audio4(stream_ctx[packet.stream_index].dec_ctx, frame,
                &got_frame, &packet);
        }
        if (ret < 0)
        {
            ffmpeg.av_frame_free(&frame);
            Console.WriteLine("Decoding failed\n");
            break;
        }
        if (got_frame != 0)
        {
            frame->pts = ffmpeg.av_frame_get_best_effort_timestamp(frame);
            ret = filter_encode_write_frame(frame, (uint)stream_index);
            // SAVE LAST FRAME/PACKET HERE
            ffmpeg.av_frame_free(&frame);
            if (ret < 0)
                goto end;
        }
        else
        {
            ffmpeg.av_frame_free(&frame);
        }
    }
    else
    {
        /* remux this frame without reencoding */
        packet.dts = ffmpeg.av_rescale_q_rnd(packet.dts,
                ifmt_ctx->streams[stream_index]->time_base,
                ofmt_ctx->streams[stream_index]->time_base,
                AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);
        packet.pts = ffmpeg.av_rescale_q_rnd(packet.pts,
                ifmt_ctx->streams[stream_index]->time_base,
                ofmt_ctx->streams[stream_index]->time_base,
                AVRounding.AV_ROUND_NEAR_INF | AVRounding.AV_ROUND_PASS_MINMAX);
        ret = ffmpeg.av_interleaved_write_frame(ofmt_ctx, &packet);
        if (ret < 0)
            goto end;
    }
    ffmpeg.av_free_packet(&packet);
}
...