Webrtc Webm(VP8/Opus)文件读写
我正在尝试用C/C++开发一个webrtc模拟器。对于媒体处理,我计划使用libav。我正在考虑以下步骤来实现两个webrtc模拟器之间的媒体交换。假设我有两个webrtc模拟器A和BWebrtc 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上提取的
或者有人能指导我开发它吗 我正在尝试一个测试程序。作为第一步,我的目标是从文件中读取并写入输出文件。我有下面的代码,但它不能正常工作
//#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;