Webrtc Webm(VP8/Opus)文件读写

Webrtc Webm(VP8/Opus)文件读写,webrtc,webm,libav,vp8,opus,Webrtc,Webm,Libav,Vp8,Opus,我正在尝试用C/C++开发一个webrtc模拟器。对于媒体处理,我计划使用libav。我正在考虑以下步骤来实现两个webrtc模拟器之间的媒体交换。假设我有两个webrtc模拟器A和B 使用av\u Read\u frameapi从输入的webm文件读取媒体 我假设我将获得编码的媒体(音频/视频)数据,我的回答正确吗 通过UDP套接字将编码的媒体数据发送到模拟器B 模拟器B以RTP数据包的形式接收UDP套接字中的媒体数据 模拟器B从刚收到的RTP数据包中提取音频/视频数据 我假设模拟器B上提取的

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

  • 使用av\u Read\u frameapi从输入的webm文件读取媒体
  • 我假设我将获得编码的媒体(音频/视频)数据,我的回答正确吗
  • 通过UDP套接字将编码的媒体数据发送到模拟器B
  • 模拟器B以RTP数据包的形式接收UDP套接字中的媒体数据
  • 模拟器B从刚收到的RTP数据包中提取音频/视频数据
  • 我假设模拟器B上提取的媒体数据仅为编码数据(此处是否正确)。我不想破译它。我想把它写入一个文件。稍后我将播放该文件,以检查我是否做了所有正确的事情
  • 为了简化这个问题,让我们去掉UDP套接字部分。然后,我的问题归结为从webm输入文件读取数据、获取编码媒体、准备数据包并使用av_交错_写入_帧或任何其他适当的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;
    }
    
    /\define\u AUDIO\u WRITE\u ENABLED_
    #包括“libavutil/imgutils.h”
    #包括“libavutil/samplefmt.h”
    #包括“libavformat/avformat.h”
    静态数据包;
    静态AVFormatContext*fmt_ctx=NULL;
    静态AVFormatContext*av_format_context=NULL;
    静态AVOutputFormat*av_输出_格式=NULL;
    静态AVCodec*视频编解码器=空;
    静态AVStream*视频_流=NULL;
    静态AVCodec*音频编解码器=空;
    静态AVStream*audio_stream=NULL;
    静态常量char*src_filename=NULL;
    静态常量字符*dst_文件名=NULL;
    int main(int argc,字符**argv)
    {
    int-ret=0;
    int指数=0;
    如果(argc!=3)
    {
    printf(“用法:./webm输入\视频\文件输出\视频\文件\n”);
    出口(0);
    }
    src_filename=argv[1];
    dst_filename=argv[2];
    printf(“源文件=%s,目标文件=%s\n”,src_文件名,dst_文件名);
    av_寄存器_all();
    /*打开输入文件,并分配格式上下文*/
    if(avformat\u open\u输入(&fmt\u ctx,src\u文件名,NULL,NULL)<0)
    {
    fprintf(stderr,“无法打开源文件%s\n”,src\u文件名);
    出口(1);
    }
    /*检索流信息*/
    如果(avformat\U find\U stream\U info(fmt\U ctx,NULL)<0)
    {
    fprintf(stderr,“找不到流信息”);
    出口(2);
    }
    av_输出_格式=av_猜测_格式(NULL,dst_文件名,NULL);
    if(!av_输出_格式)
    {
    fprintf(stderr,“无法猜测输出文件格式”\n);
    出口(3);
    }
    av_输出格式->音频编解码器=av_编解码器\u ID\u VORBIS;
    av_输出_格式->视频_编解码器=av_编解码器_ID_VP8;
    av_format_context=avformat_alloc_context();
    如果(!av_格式_上下文)
    {
    fprintf(stderr,“无法分配av格式上下文\n”);
    出口(4);
    }   
    av_格式\u上下文->oformat=av_输出\u格式;
    strcpy(av_格式_上下文->文件名,dst_文件名);
    视频编解码器=avcodec\U查找编码器(av\U输出\U格式->视频编解码器);
    if(!视频编解码器)
    {
    fprintf(stderr,“找不到编解码器”);
    出口(5);
    }
    视频\流=AVU格式\新\流(av \格式\上下文,视频\编解码器);
    如果(!视频流)
    {
    fprintf(stderr,“无法分配流”\n);
    出口(6);
    }
    avcodec\u get\u context\u defaults3(视频流->编解码器,视频编解码器);
    视频流->编解码器->编解码器id=AV\U编解码器id\U VP8;
    视频\u流->编解码器->编解码器\u类型=AVMEDIA\u类型\u视频;
    视频流->时间基=(AVRational){1,30};
    视频流->编解码器->宽度=640;
    视频流->编解码器->高度=480;
    视频流->编解码器->pix\U fmt=pix\U fmt\U YUV420P;
    视频流->编解码器->标志|=编解码器标志|全局标题;
    视频流->编解码器->比特率=400000;
    视频流->编解码器->gop\U大小=10;
    视频流->编解码器->最大帧数=1;
    #ifdef(音频)(写入)(已启用)
    音频编解码器=avcodec\U查找编码器(av\U输出\U格式->音频编解码器);
    如果(!音频_编解码器)
    {
    fprintf(stderr,“未找到编解码器音频编解码器”);
    出口(5);
    }
    音频\流=AVU格式\新\流(av \格式\上下文,音频\编解码器);
    如果(!音频_流)
    {
    fprintf(stderr,“无法为音频分配流\n”);
    出口(6);
    }
    avcodec_get_context_defaults3(音频流->编解码器,音频编解码器);
    音频流->编解码器->编解码器id=AV编解码器id\U VORBIS;
    音频\流->编解码器->编解码器\类型=AVMEDIA \类型\音频;
    音频流->时间基=(AVRational){1,30};
    音频流->编解码器->采样率=8000;
    音频流->编解码器->标志|=编解码器标志|全局标题;
    #恩迪夫
    if(!(av_输出格式->标志和AVFMT_文件))
    {
    如果(avio_打开(&av_格式_上下文->pb,dst_文件名,avio_标志_写入)<0)
    {
    fprintf(stderr,“无法打开“%s”\n”,dst_文件名);
    }
    }
    /*在avformat_write_头设置流之前*/
    avformat_write_头(av_格式_上下文,空);
    /*初始化数据包,将数据设置为NULL,让解复用器填充它*/
    av_初始_数据包(&pkt);
    pkt.data=NULL;
    pkt.size=0;
    pkt.stream\u index=视频流->索引;
    ret=av读取帧(fmt、ctx和pkt);
    而(ret>=0)
    {
    索引++;
    //pkt.stream\u index=video\u avstream->index;
    如果(pkt.stream\u index==视频流->索引)
    {
    printf(“视频:读取周期%d,读取字节=%d,pkt流索引=%d\n”,索引,pkt.size,pkt.stream\u索引);
    av_写入_帧(av_格式_
    
    #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;