C/C++ で webrtc シミュレーターを開発しようとしています。メディアの取り扱いには、libavを使用する予定です。2つのwebrtcシミュレーター間のメディア交換を実現するために、以下の手順を考えています。2 つの webrtc シミュレーターAとBがあるとします。
- av_read_frame apiを使用して、入力 webm ファイルから A でメディアを読み取ります。
- エンコードされたメディア (オーディオ/ビデオ) データを取得すると思いますが、これでよろしいですか?
- エンコードされたメディア データをUDP ソケット経由でシミュレータBに送信します。
- シミュレータBはメディア データを UDP ソケットで RTP パケットとして受信します。
- シミュレータBは、受信したばかりの RTP パケットからオーディオ/ビデオ データを抽出します。
- シミュレータ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;
}
このプログラムを実行すると、「コーデックが見つかりません」と出力されます。何がうまくいかないのか、誰か助けてください。
コーデックが見つからない問題は、libvpx1.4 バージョンを個別にビルドすることで解決されます。ソースファイルからの読み取りと宛先ファイルへの書き込みにまだ苦労しています。
編集 1: コードの変更後、ファイルに書き込むことができるのはビデオのみですが、さらにいくつかのエラーがまだ存在します。
編集 2: 修正されたコード (2 回目) を使用すると、ビデオ フレームが正しく書き込まれていることがわかります。オーディオ フレームの場合、マクロ_AUDIO_WRITE_ENABLED_の下にコードを追加しました が、このマクロ プログラムを有効にするとクラッシュします。誰かがオーディオ書き込み部分 (マクロ _AUDIO_WRITE_ENABLED_ の下のコード) で何が問題なのかを案内できますか?