【问题标题】:Webm (VP8 / Opus) file read and write backWebm (VP8 / Opus) 文件读写
【发布时间】:2015-09-11 11:37:48
【问题描述】:

我正在尝试用 C/C++ 开发一个 webrtc 模拟器。对于媒体处理,我打算使用 libav。我正在考虑以下步骤来实现两个 webrtc 模拟器之间的媒体交换。假设我有两个 webrtc 模拟器 AB

  1. 使用 av_read_frame api 从输入 webm 文件中读取 A 处的媒体。
  2. 我假设我将获得编码的媒体(音频/视频)数据,我在这里正确吗?
  3. 通过 UDP 套接字将编码的媒体数据发送到模拟器 B
  4. 模拟器 B 接收 UDP 套接字中的媒体数据作为 RTP 数据包。
  5. 模拟器B从刚收到的RTP包中提取音频/视频数据。
  6. 我假设在模拟器 B 中提取的媒体数据只是编码数据(我在这里说得对吗)。我不想解码它。我想把它写到一个文件中。稍后我将播放该文件以检查我是否已正确完成所有操作。

为了简化这个问题,让我们去掉 UDP 套接字部分。然后我的问题简化为从 webm 输入文件读取数据,获取编码媒体,准备数据包并使用 av_interleaved_write_frame 或任何其他适当的 api 写入输出文件。所有这些我想用 libav 做的事情。

有没有我可以参考的示例代码。
或者有人可以指导我开发它。

我正在尝试一个测试程序。作为第一步,我的目标是读取文件并写入输出文件。我有下面的代码,但它不能正常工作。

//#define _AUDIO_WRITE_ENABLED_

#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
#include "libavformat/avformat.h"

static AVPacket pkt;
static AVFormatContext *fmt_ctx = NULL;
static AVFormatContext *av_format_context = NULL;
static AVOutputFormat *av_output_format = NULL;

static AVCodec *video_codec = NULL;
static AVStream *video_stream = NULL;

static AVCodec *audio_codec = NULL;
static AVStream *audio_stream = NULL;


static const char *src_filename = NULL;
static const char *dst_filename = NULL;

int main (int argc, char **argv)
{
    int ret = 0;
    int index = 0;

    if (argc != 3) 
    {
        printf("Usage: ./webm input_video_file output_video_file \n");
        exit(0);
    }

    src_filename = argv[1];
    dst_filename = argv[2];

    printf("Source file = %s , Destination file = %s\n", src_filename, dst_filename);

    av_register_all();

    /* open input file, and allocate format context */
    if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) 
    {
        fprintf(stderr, "Could not open source file %s\n", src_filename);
        exit(1);
    }

    /* retrieve stream information */
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) 
    {
        fprintf(stderr, "Could not find stream information\n");
        exit(2);
    }

    av_output_format = av_guess_format(NULL, dst_filename, NULL);
    if(!av_output_format)
    {
        fprintf(stderr, "Could not guess output file format\n");
        exit(3);
    }

    av_output_format->audio_codec = AV_CODEC_ID_VORBIS;
    av_output_format->video_codec = AV_CODEC_ID_VP8;

    av_format_context = avformat_alloc_context();
    if(!av_format_context) 
    {
        fprintf(stderr, "Could not allocation av format context\n");
        exit(4);
    }   
    av_format_context->oformat = av_output_format;
    strcpy(av_format_context->filename, dst_filename);


    video_codec = avcodec_find_encoder(av_output_format->video_codec);
    if (!video_codec) 
    {
        fprintf(stderr, "Codec not found\n");
        exit(5);
    }

    video_stream = avformat_new_stream(av_format_context, video_codec);
    if (!video_stream) 
    {
        fprintf(stderr, "Could not alloc stream\n");
        exit(6);
    }

    avcodec_get_context_defaults3(video_stream->codec, video_codec);
    video_stream->codec->codec_id = AV_CODEC_ID_VP8;
    video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO;

    video_stream->time_base = (AVRational) {1, 30};   

    video_stream->codec->width = 640; 
    video_stream->codec->height = 480; 

    video_stream->codec->pix_fmt = PIX_FMT_YUV420P;
    video_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
    video_stream->codec->bit_rate = 400000;
    video_stream->codec->gop_size = 10;
    video_stream->codec->max_b_frames=1;

#ifdef _AUDIO_WRITE_ENABLED_    
    audio_codec = avcodec_find_encoder(av_output_format->audio_codec);
    if (!audio_codec) 
    {
        fprintf(stderr, "Codec not found audio codec\n");
        exit(5);
    }


    audio_stream = avformat_new_stream(av_format_context, audio_codec);
    if (!audio_stream) 
    {
        fprintf(stderr, "Could not alloc stream for audio\n");
        exit(6);
    }

    avcodec_get_context_defaults3(audio_stream->codec, audio_codec);
    audio_stream->codec->codec_id = AV_CODEC_ID_VORBIS;
    audio_stream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
    audio_stream->time_base = (AVRational) {1, 30};
    audio_stream->codec->sample_rate = 8000;
    audio_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
#endif

    if(!(av_output_format->flags & AVFMT_NOFILE)) 
    {
        if (avio_open(&av_format_context->pb, dst_filename, AVIO_FLAG_WRITE) < 0)
        {
            fprintf(stderr, "Could not open '%s'\n", dst_filename);
        }
    }

    /* Before avformat_write_header set the stream */
    avformat_write_header(av_format_context, NULL);

    /* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    pkt.stream_index = video_stream->index;

    ret = av_read_frame(fmt_ctx, &pkt);
    while (ret >= 0) 
    {
        index++;

        //pkt.stream_index = video_avstream->index;
        if(pkt.stream_index == video_stream->index)
        {
            printf("Video: Read cycle %d, bytes read = %d, pkt stream index=%d\n", index, pkt.size, pkt.stream_index);
            av_write_frame(av_format_context, &pkt);
        }
#ifdef _AUDIO_WRITE_ENABLED_        
        else if(pkt.stream_index == audio_stream->index)
        {
            printf("Audio: Read cycle %d, bytes read = %d, pkt stream index=%d\n", index, pkt.size, pkt.stream_index);
            av_write_frame(av_format_context, &pkt);
        }
#endif        
        av_free_packet(&pkt);
        ret = av_read_frame(fmt_ctx, &pkt);
    }

    av_write_trailer(av_format_context);

    /** Exit procedure starts */
    avformat_close_input(&fmt_ctx);
    avformat_free_context(av_format_context);

    return 0;
}

当我执行这个程序时,它输出“codec not found”。现在确定出了什么问题,有人可以帮忙吗。

Codec not found 问题已通过单独构建 libvpx1.4 版本解决。仍在努力从源文件读取,并写入目标文件。

编辑 1:代码修改后,我只能将视频内容写入文件,但仍然存在更多错误。

编辑 2:使用修改后的代码(第二轮),我看到视频帧写入正确。对于音频帧,我在宏 _AUDIO_WRITE_ENABLED_ 下添加了代码,但如果我启用此宏程序崩溃。有人可以指导音频写入部分的问题(宏_AUDIO_WRITE_ENABLED_下的代码)。

【问题讨论】:

    标签: webrtc webm libav vp8 opus


    【解决方案1】:

    我没有完全回答你的问题,但我希望我们最终能找到最终的解决方案。当我尝试运行您的代码时,我收到此错误“time base not set”。

    时基和其他标头规范是编解码器的一部分。这就是,我如何将这个东西指定为写入文件(vStreamAVStream):

    #if LIBAVCODEC_VER_AT_LEAST(53, 21)
        avcodec_get_context_defaults3(rc->vStream->codec, AVMEDIA_TYPE_VIDEO);
    #else
        avcodec_get_context_defaults2(rc->vStream->codec, AVMEDIA_TYPE_VIDEO);
    #endif
    #if LIBAVCODEC_VER_AT_LEAST(54, 25)
        vStream->codec->codec_id = AV_CODEC_ID_VP8;
    #else
        vStream->codec->codec_id = CODEC_ID_VP8;
    #endif
        vStream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
        vStream->codec->time_base = (AVRational) {1, 30};   
        vStream->codec->width = 640; 
        vStream->codec->height = 480; 
        vStream->codec->pix_fmt = PIX_FMT_YUV420P;
    

    编辑:我在 Valgrind 中运行了你的程序,它在 av_write_frame 上出现了段错误。看起来它的 time_base 和其他输出规范设置不正确。 在avformat_write_header() 之前添加规格,以免为时已晚。

    【讨论】:

    • 我已根据建议修改了代码(如上所示)。但是在尝试写入标题时它仍然崩溃。有没有合适的例子。我遇到了 ffmpeg.org/doxygen/0.6/output-example_8c-source.html ,但它再次具有编码内容。我想从输入文件中读取数据,获取数据(我将通过 UDP 发送并远程接收这些数据),将数据写入文件。
    • 我已经修改了代码(在原始问题部分更新)并且能够避免崩溃。但我还有两个问题。 1.只写入视频数据,听不到任何音频数据(可能我需要为音频内容添加代码),2.文件末尾无法播放。它说“无法解码帧”。
    • 使用 revisio 2,看起来我能够读取和写回视频帧。我正在尝试音频帧写入(请参阅代码中的宏 AUDIO_WRITE_ENABLED),然后程序崩溃..,任何线索...谢谢
    • 我在 libav 中看到了 cue 操作的崩溃。现在确定我是否需要调用/设置特定的提示。
    • 我在libav.org/doxygen/master/examples.html 得到了一个类似(有点不同)的例子。 ,在那个 output.c 文件中正在做一些类似的事情。我会检查并尝试理解。可能在那之后我将能够想出测试代码。
    猜你喜欢
    • 2015-08-31
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 2021-02-05
    • 1970-01-01
    • 2021-03-26
    相关资源
    最近更新 更多