2015-06-25 10 views
0

Я пытаюсь разработать симулятор webrtc в C/C++. Для обработки мультимедиа я планирую использовать libav. Я думаю о нижеследующих шагах по реализации медиа-обмена между двумя симуляторами webrtc. Скажем, у меня есть два тренажера webrtc A и B.Чтение и запись файла Webm (VP8/Opus)

  1. Чтение СМИ в A из входного файла WebM с помощью av_read_frame апи.
  2. Я предполагаю, что получу данные закодированного носителя (аудио/видео), Я исправлю здесь?
  3. Передача кодированных мультимедийных данных в тренажер B через разъем UDP.
  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; 
} 

При выполнении этой программы он выводит «кодек не найден». Теперь уверен, что идет не так, Может кто-нибудь помочь, пожалуйста.

Проблема с кодеком не решена путем разблокировки версии libvpx1.4. Все еще изо всех сил пытается читать исходный файл и записывать в файл назначения.

EDIT 1: После изменения кода, только видеоматериалы, которые я могу записать в файл, хотя еще есть некоторые ошибки.

EDIT 2: с измененным кодом (2-й раунд), я вижу, что видеокадры написаны правильно. Для аудиокадров я добавил код под макросом _AUDIO_WRITE_ENABLED_, но если я включу эту программу для макросов. Может ли кто-нибудь руководствоваться ошибкой в ​​части записи звука (код под макросом _AUDIO_WRITE_ENABLED_).

ответ

0

Я не полностью отвечаю на ваш вопрос, но надеюсь, что мы в конечном итоге достигнем окончательного решения. Когда я попытался запустить ваш код, я получил эту ошибку «time base not set».

Временная база и другие спецификации заголовков являются частью кодека.Это, как у меня есть эта вещь, указанная для записи в файл (vStream имеет 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; 

EDIT: Я побежал программу в Valgrind и на av_write_frame ошибка сегментация. Похоже, что time_base и другие спецификации для вывода не установлены должным образом. Добавить спецификации до avformat_write_header(), пока не стало слишком поздно.

+0

У меня есть модифицированный код (приведенный выше) в соответствии с предложением. Но все равно он рушится, пытаясь написать заголовок. Есть ли подходящий пример. Я наткнулся на https://www.ffmpeg.org/doxygen/0.6/output-example_8c-source.html, но он снова имеет кодировку. Я хочу читать из входного файла, получать данные (эти данные я буду отправлять по UDP и получать с удаленного), записывать данные в файл. – Kamal

+0

У меня есть модифицированный код (обновлен в исходном разделе вопросов) и вы можете избежать сбоя. Но у меня еще есть еще две проблемы. 1. Запись только видеоданных, не слышно аудиоданных (может быть, мне нужно добавить код для аудиофайлов), 2. К концу файла он не может играть. В нем говорится: «Не удалось декодировать фрейм». – Kamal

+0

С revisio 2, похоже, я умею читать и записывать видеоролики. Я пытаюсь записать звуковой кадр (см. Макрос _AUDIO_WRITE_ENABLED_ в коде), затем программа сбой .., любая подсказка ... спасибо – Kamal