Давайте рассмотрим этот очень хороший и простой в использовании пример remux от horgh .
Я бы хотел решить ту же задачу: преобразовать кодированный поток RTSP H264 в фрагментированный поток MP4 , Этот код выполняет именно эту задачу.
Однако я вообще не хочу записывать mp4 на диск, но мне нужно получить байтовый буфер или массив в C с содержимым, которое обычно записывается в диск.
Как это возможно? В этом примере vs_open_output используется для определения выходного формата, а для этой функции необходим выходной URL.
Если бы я избавился от вывода содержимого на диск, как мне изменить этот код? Или, возможно, есть и лучшие альтернативы, которые также приветствуются.
Обновление:
Как рекомендовал szatmary, я проверил его пример ссылки .
Однако, как я уже сказал в вопросе, мне нужен вывод в виде буфера, а не файла. Этот пример наглядно демонстрирует, как я могу прочесть свой пользовательский источник и передать его в ffmpeg.
Что мне нужно, так это как открыть входные данные в стандартном режиме (с помощью avformat_open_input ), а затем выполнить мои пользовательские изменения с помощью пакеты и затем вместо записи в файл, записи в буфер.
Что я пробовал?
На основе примера szatmary я создал несколько буферов и инициализацию:
uint8_t *buffer;
buffer = (uint8_t *)av_malloc(4096);
format_ctx = avformat_alloc_context();
format_ctx->pb = avio_alloc_context(
buffer, 4096, // internal buffer and its size
1, // write flag (1=true, 0=false)
opaque, // user data, will be passed to our callback functions
0, // no read
&IOWriteFunc,
&IOSeekFunc
);
format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO;
AVOutputFormat * const output_format = av_guess_format("mp4", NULL, NULL);
format_ctx->oformat = output_format;
avformat_alloc_output_context2(&format_ctx, output_format,
NULL, NULL)
Затем, конечно, я создал 'IOWriteFun c' и 'IOSeekFun c':
static int IOWriteFunc(void *opaque, uint8_t *buf, int buf_size) {
printf("Bytes read: %d\n", buf_size);
int len = buf_size;
return (int)len;
}
static int64_t IOSeekFunc (void *opaque, int64_t offset, int whence) {
switch(whence){
case SEEK_SET:
return 1;
break;
case SEEK_CUR:
return 1;
break;
case SEEK_END:
return 1;
break;
case AVSEEK_SIZE:
return 4096;
break;
default:
return -1;
}
return 1;
}
Затем мне нужно записать заголовок в выходной буфер, и ожидаемое поведение здесь - напечатать "Чтение байтов: x" :
AVDictionary * opts = NULL;
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
av_dict_set_int(&opts, "flush_packets", 1, 0);
avformat_write_header(output->format_ctx, &opts)
В последней строке во время выполнения всегда возникает ошибка seg, вот обратная трассировка:
#0 0x00007ffff7a6ee30 in () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
#1 0x00007ffff7a98189 in avformat_init_output () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
#2 0x00007ffff7a98ca5 in avformat_write_header () at /usr/lib/x86_64-linux-gnu/libavformat.so.57
...
Трудно для меня с примером в том, что он использует avformat_open_input .
Однако такого вывода для вывода не существует (нет avformat_open_ouput ).
Update2:
Я нашел Ano Пример для чтения: doc / examples / avio_reading. c.
Есть упоминания о похожем примере для записи (avio_writing. c), но ffmpeg не имеет этого доступно (по крайней мере, в моем поиске Google).
Эта задача действительно трудно решить? стандартный ввод rtsp для пользовательского avio?
К счастью, ffmpeg.org не работает. Отлично.