Моя цель - транслировать mpegts. В качестве входных данных я беру поток файлов mp4. То есть производитель видео записывает mp4 файл в поток, с которым я пытаюсь работать. Видео может длиться от одной минуты до десяти минут. Поскольку производитель записывает байты в поток, первоначально записанный заголовок mp4 не является полным (первые 32 байта до ftyp равны 0x00, потому что он еще не знает различных смещений... которые, я думаю, записываются после записи):
Вот как выглядит заголовок типичного mp4:
00 00 00 18 66 74 79 70 69 73 6f 6d 00 00 00 00 ....ftypisom....
69 73 6f 6d 33 67 70 34 00 01 bb 8c 6d 64 61 74 isom3gp4..»Œmdat
Вот как выглядит заголовок «в процессе» mp4:
00 00 00 00 66 74 79 70 69 73 6f 6d 00 00 00 00 ....ftypisom....
69 73 6f 6d 33 67 70 34 00 00 00 18 3f 3f 3f 3f isom3gp4....????
6d 64 61 74 mdat
Это мое предположение, но я предполагаю, что как только производитель завершает запись, он обновляет заголовок, записывая все необходимые смещения.
При попытке выполнить эту работу я столкнулся с двумя проблемами:
- Я создал собственный AVIO с функцией чтения, которая не поддерживает поиск. В моей программе-драйвере я решил транслировать правильно отформатированный файл mp4. Я могу определить его формат ввода. Когда я пытаюсь открыть его, я вижу, что моя пользовательская функция чтения выполняется в avformat_open_input до тех пор, пока не будет прочитан весь файл.
Мой пример кода:
av_register_all();
AVFormatContext* pCtx = avformat_alloc_context();
pCtx->pb = avio_alloc_context(
pBuffer, // internal buffer
iBufSize, // internal buffer size
0, // bWriteable (1=true,0=false)
stream, // user data ; will be passed to our callback functions
read_stream, // read callback function
NULL, // write callback function (not used in this example)
NULL // seek callback function
);
pCtx->pb->seekable = 0;
pCtx->pb->write_flag = 0;
pCtx->iformat = av_find_input_format( "mp4" );
pCtx->flags |= AVFMT_FLAG_CUSTOM_IO;
avformat_open_input( &pCtx, "", pCtx->iformat, NULL );
Очевидно, это не работает так, как мне нужно (я не оправдал ожиданий). Как только я заменяю файл конечного размера потоком различной длины, я не могу заставить avformat_open_input ждать завершения потока, прежде чем пытаться выполнить дальнейшую обработку.
Таким образом, мне нужно найти способ открыть ввод без попытки его чтения и читать только при выполнении av_read_frame. Возможно ли это сделать с помощью пользовательского AVIO. То есть подготовить/открыть ввод -> прочитать начальные входные данные во входной буфер -> прочитать кадр/пакет из входного буфера -> записать пакет на выход -> повторить чтение входных данных до конца потока.
Я покопался в Google и увидел только две альтернативы: предоставление собственного URLProtocol и использование AVFMT_NOFILE.
Пользовательский URL-протокол
Это звучит как немного обратный путь к тому, что я пытаюсь выполнить. Я понимаю, что его лучше всего использовать, когда доступен источник файла. В то время как я пытаюсь читать из потока байтов. Кроме того, еще одна причина, по которой я думаю, что это не соответствует моим потребностям, заключается в том, что пользовательский URLProtocol необходимо скомпилировать в библиотеку ffmpeg, верно? Или есть способ вручную зарегистрировать его во время выполнения?
AVFMT NOFILE
Мне кажется, это должно работать лучше всего. Сам флаг говорит об отсутствии базового исходного файла и предполагает, что я возьму на себя все операции чтения и предоставления входных данных. Проблема в том, что я пока не видел фрагментов кода в Интернете, но мое предположение таково:
Я действительно надеюсь получить некоторые предложения пищи для мозга от кого-либо, потому что я новичок в ffmpeg и цифровых медиа, и моя вторая проблема предполагает, что я могу передавать поток вывода во время приема ввода.
Как я упоминал выше, у меня есть дескриптор потока байтов файла mp4, поскольку он будет записан на жесткий диск. Формат mp4 (h.264 и aac). Мне нужно преобразовать его в mpegts перед потоковой передачей. Это не должно быть сложно, потому что mp4 и mpegts — это просто контейнеры. Из того, что я узнал до сих пор, файл mp4 выглядит следующим образом:
[информация заголовка, содержащая версии формата]
mdat
[данные потока, в моем случае потоки h.264 и aac]
[какой-то разделитель трейлера]
[данные трейлера]
Если это правильно, я должен получить дескриптор чередующихся данных h.264 и aac, просто начав читать поток после идентификатора «mdat», верно?
Если это правда, и я решил использовать подход AVFMT_NOFILE для управления входными данными, я могу просто принять потоковые данные (в буфер AVFormatContext) -> av_read_frame -> обработать его -> заполнить AVFormatContext дополнительными данными -> av_read_frame -> и так далее до конца стрима.
Я знаю, что это полный рот и свалка моих мыслей, но я был бы признателен за любое обсуждение, указатели, мысли!