Webm(VP8/Opus)文件读写 [英] Webm (VP8 / Opus) file read and write back

查看:275
本文介绍了Webm(VP8/Opus)文件读写的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to develop a webrtc simulator in C/C++. For media handling, I plan to use libav. I am thinking of below steps to realize media exchange between two webrtc simulator. Say I have two webrtc simulators A and B.

  1. 使用 av_read_frame API从输入的webm文件中读取A处的媒体.
  2. 我想我将获得编码的媒体(音频/视频)数据,我在这里纠正吗?
  3. 通过UDP套接字将编码的媒体数据发送到模拟器 B .
  4. 模拟器 B 接收UDP套接字中的媒体数据作为RTP数据包.
  5. 模拟器 B 从刚刚接收到的RTP数据包中提取音频/视频数据.
  6. 我假定在模拟器 B 处提取的媒体数据仅是编码数据(我在这里正确).我不想解码它.我想将其写入文件.稍后,我将播放该文件,以检查我是否做对了所有事情.
  1. Read media at A from a input webm file using av_read_frame api.
  2. I assume I will get the encoded media (audio / video) data, am I correct here?
  3. Send the encoded media data to simulator B over a UDP socket.
  4. Simulator B receives the media data in UDP socket as RTP packets.
  5. Simulator B extracts audio/video data from just received RTP packet.
  6. I assume the extracted media data at simulator B are the encoded data only (am I correct here). I do not want to decode it. I want to write it to a file. Later I will play the file to check if I have done everything right.

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

To simplify this problem lets take out UDP socket part. Then my question reduces to read data from a webm input file, get the encoded media, prepare the packet and write to a output file using av_interleaved_write_frame or any other appropriate api. All these things I want to do using libav.

有没有我可以参考的示例代码.
或者有人可以指导我进行开发.

Is there any example code I can refer.
Or can somebody please guide me to develop it.

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

I am trying with a test program. As a first step, my aim is to read from a file and write to an output file. I have below code, but it is not working properly.

//#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;
}

当我执行该程序时,它输出找不到编解码器".现在确定出了什么问题,请帮忙.

When I execute this program, it outputs "codec not found". Now sure whats going wrong, Can somebody help please.

找不到编解码器的问题通过单独构建libvpx1.4版本解决.仍在努力读取源文件并写入目标文件.

Codec not found issue is resolved by separately building libvpx1.4 version. Still struggling to read from source file, and writing to a destination file.

代码修改后,尽管有些错误仍然存​​在,但我只能将视频内容写入文件.

EDIT 1: After code modification, only video stuff I am able to write to a file, though some more errors are still present.

使用修改后的代码(第2轮),我看到视频帧已正确写入.对于音频帧,我在宏 _AUDIO_WRITE_ENABLED _ 下添加了代码,但是如果启用此宏程序,则会崩溃.有人可以指导音频写入部分出什么问题吗(宏_AUDIO_WRITE_ENABLED_下的代码).

EDIT 2: With modified code (2nd round), I see video frames are written properly. For audio frames I added the code under a macro _AUDIO_WRITE_ENABLED_ , but if I enable this macro program crashing. Can somebody guide whats wrong in audio write part (code under macro _AUDIO_WRITE_ENABLED_).

推荐答案

我没有完全回答您的问题,但是我希望我们最终能得到最终的解决方案.当我尝试运行您的代码时,出现此错误"time base not set".

I am not fully answering your question, but I hope we will get to the final solution eventually. When I tried to run your code, I got this error "time base not set".

时基和其他标头规范是编解码器的一部分.这就是我如何指定要写入文件的内容(vStreamAVStream):

Time base and other header specs are part of codec. This is, how I have this thing specified for writing into file (vStream is of AVStream):

#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()之前添加规格,以免为时已晚.

I ran your program in Valgrind and it segfaults on av_write_frame. Looks like its time_base and other specs for output are not set properly. Add the specs before avformat_write_header(), before it is too late.

这篇关于Webm(VP8/Opus)文件读写的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆