Войти
ПрограммированиеФорумОбщее

Как обернуть h264 в mp4?

Страницы: 1 2 Следующая »
#0
20:13, 11 янв. 2021

У меня генерируется видеофайл в формате h264, но не всякий плейер его понимает, поэтому я хочу его преобразовать к mp4.

Это можно сделать с помощью FFmpeg командой "ffmpeg -i orig.264 -vcodec copy out.mp4" и это отлично работает, но я не хочу совать в проект FFmpeg с его лицензией.

Поэтому попробовал сделать это програмно, но закопался. Собственно FFmpeg просто формирует некий хедер, потом копирует исходный файл как есть и в конце что-то еще добавляет. По идее это должно быть просто, но непонятно что он там пишет. Посмотреть FFmpeg в отладчике нереально - там мегатонна кода на C для компилятора командной строки и сконвертить это в формат VS не представляется возможным (за разумное время).

Нашел еще библиотеку попроще - libmp4v2, на ней нашел пример как из h264 сделать mp4, и даже сделал, но она преобразует данные, т.е. кодирует поток по новому, вместо того, что бы просто копировать. При этом файл играется со скоростью которая была при записи h264, что меня категорически не устраивает, поскольку формирование видеокадров у меня идет не в реалтайм и воспроизведение получается медленно и с рывками.

Короче нужно сделать так же, как делает FFmpeg с кодеком "copy".  Кто нибудь в курсе как это можно решить?


#1
22:10, 11 янв. 2021

А ОС какая? Если только Windows, то есть Media Foundation.
Для записи в mp4 нужно использовать соответствующий sink.
https://docs.microsoft.com/en-us/windows/win32/api/mfidl/nf-mfidl… peg4mediasink

Но вообще было бы проще и логичнее сразу при генерации видео записывать его в нужный контейнер, например, с помощью того же Media Foundation.

#2
22:16, 11 янв. 2021

mp4 - это всего лишь контейнер, а не формат, такой же как mkv, например.  Можно использовать mp4box или gpac, например, чтобы замерджить h264  в mp4 (он же mpv). Чтобы замерджить в mkv - есть официальная утилита  mkvmerge

#3
23:33, 11 янв. 2021

CapSopener
>Но вообще было бы проще и логичнее сразу при генерации видео записывать его в нужный контейнер, например, с помощью того же Media Foundatio
Вы это обьясните разработчикам видеокарт... Аппаратное кодирование идет только в форматы h264/h265. Причем файлы у AMD и MVIDIA получаются не совсем идентичными - NVIDIA играется на VLC а AMD нет. Хотя после преобразования к mp4 и тот и другой нормально показываются.

>есть Media Foundation.
ОК, а можно примерчик как с ее помощью обернуть h264 в mp4?

0iStalker
>mp4 - это всего лишь контейнер, а не формат, такой же как mkv, например.
Ну я вообще-то в курсе. Я же сказал, что мне нужно ОБЕРНУТЬ h264 в MP4. Что и делает FFmpeg с кодеком copy. Но мне нужна не утилита а функция в программе на C++.

#4
(Правка: 23:53) 23:51, 11 янв. 2021

san
> Я же сказал, что мне нужно ОБЕРНУТЬ h264 в MP4. Что и делает FFmpeg с кодеком
> copy. Но мне нужна не утилита а функция в программе на C++.
>

Вообще говоря, есть стандарт на формат файла (не особо сложный, для реализации, на первый взгляд)

https://xhelmboyx.tripod.com/formats/mp4-layout.txt
https://web.archive.org/web/20180219054429/http://l.web.umkc.edu/… n/ref/mp4.pdf
https://github.com/OpenAnsible/rust-mp4/raw/master/docs/ISO_IEC_1… 003-11-15.pdf

+

https://developer.apple.com/library/archive/documentation/QuickTi… 939-CH204-SW1

#5
0:02, 12 янв. 2021

0iStalker
> Вообще говоря, есть стандарт на формат файла (не особо сложный, для реализации, на первый взгляд)
Ну если он такой несложный, то покажите как это сделать. Я пока не нашел на просторах интернета ни одного рабочего примера.

#6
12:27, 12 янв. 2021

san
> У меня генерируется видеофайл в формате h264, но не всякий плейер его понимает,
> поэтому я хочу его преобразовать к mp4.

h264 насколько мне известно - это просто сырой поток сжатых видеоданных. Делал декодер на нём.

Тоже хотел обернуть его в контейнер, но потом забил.

Тем более,  MPC HC понимает h264 raw data. Ну и упомянутый FFMPEG тоже :)

#7
(Правка: 14:42) 14:33, 12 янв. 2021

занимался немного на прошлой работе этим, в чем суть:

Энкодеры у тебя принимают изображение, порой даже не в RGBA, а в YUV формате (I420, NV21/NV12 и подобных(особенно аппаратные) и если ты не отдаешь в нем сам, то втихаря за тебя конвертят и не факт, что самым оптимальным образом ) отдают тебе  закодированные данные (кадр + служебные данные) и метки времени/номера к ним
*.h264 - это dump потока из энкодера только закодированных данных, причем без меток времени (разделены юниты между друг друга разделителем 0x00 0x00 0x00 0x01). Так же хочу заметить, что кадры из энкодера могут идти не в хронологическом порядке (B-frame) и не всегда преобразованный h264->mp4 будет корректно проигрываться, ибо надо парсить кишки кадров, какой от какого зависит. Плюс даже если все кадры одинаковой длины по времени, то фрейм-рейт тебе надо самом знать и задавать его как опцию конвертации, в h264 его опять же нет.

MP4/AVI и прочее - это контейнер для хранения данных. Процесс упаковки закодированных данных в контейнер - это muxing. Особенность mp4 - это то, что хранение служебной инфы для декодирования h264 и h265 nal uint-ы (sps/pps и в случае h265 - vps )  лежат отдельно от видео потока, а именно в mp4 хидере. Поэтому, когда ты работаешь с ffmpeg, тебе надо перехватить из видео потока sps/pps/vps и скормить их отдельно, ( при инициалиазции контейнера что-ли, тут уже сам разберешься), а затем уже отдавать закодированные кадры, выкидывая из них эти служебные nal-unit(ы), отдавать надо закодированные кадры + метку времени.


Изображение

Собственно ни что тебе не мешает использовать какую-угодно библиотеку для (де)контейнеризации твои данных и какой угодно (де)кодер. Есть конечно особенности некоторых видео контейнеров и сетевых стримовых протоколов, которые ориентированны на свои группы форматов и прям совсем что угодно во что угодно ты не запишешь, но h264 можно почти во что угодно записать и как угодно передать.

З.Ы. Может вечером дома найду в закромах немного сырцов.
З.З.Ы энкодер от NVidia (NVEnc) или с мобилок?

#8
17:37, 12 янв. 2021

MAMOHT-92
> h264 - это dump потока из энкодера только закодированных данных, причем без меток времени
Самое интересное, что в случае аппаратного энкодинга на AMD эти метки времени (или информация о длительности записи) мистическим образом присутствует. По крайней мере при транскодинге библиотекой MP4V2 файл формата mp4 играется в темпе создания исходного потока. В случае Nvidia этого нет.

>что тебе не мешает использовать какую-угодно библиотеку для (де)контейнеризации твои данных и какой угодно (де)кодер.
Мешает отсутствие вышеупомянутых библиотек. Нашел только MP4V2, но она со странностями. FFmpeg работает безупречно но это программа а не библиотека.

#9
17:41, 12 янв. 2021

san
> FFmpeg работает безупречно но это программа а не библиотека.
Это библиотека в первую очередь. Программа там — просто дополнительная утилита поверх библиотеки.

#10
(Правка: 18:03) 17:57, 12 янв. 2021

san
> По крайней мере при транскодинге библиотекой MP4V2 файл формата mp4 играется в
> темпе создания исходного потока. В случае Nvidia этого нет.
не уверен на 100%, есть ли в sps/pps какая-то информация о фреймрейте, но вроде я этого не помню. В общем забей, это все равно неправильный способ. ffmpeg - это классная библиотека по возможностям. Я понял, гугли как "libav". Более того, тебе все равно придется разобраться, как работает время в mp4 файле, что такое: timebase, timestamp какие там множители и что на что делится/умножается. Более того, если ты будешь работать уже с энкодерами, то работа со временем станет обязательной, ибо от корректно заданного timestamp и timebase зависит соблюдение bitrate. Иначе ты получишь перешакаленное или недожатое видео в лучшем случае.

З.Ы. я bento4  сильно переделывал, ибо там muxing какой-то "тупорылый", а мне нужна запись файла налету, можешь с ней немного поэкспериментировать, там в ней есть парсер h264 / h265 потока из памяти.

библиотека занимающаяся (de)muxing  в ffmpeg - это libavformat.

Вот какой-то кусочек из интернета:

case AV_CODEC_ID_H264:
            c->codec_type = AVMEDIA_TYPE_VIDEO;
            c->profile = FF_PROFILE_H264_HIGH;
            c->pix_fmt = AV_PIX_FMT_YUV420P;
            c->framerate = (AVRational){ 640, 19200 };
            c->bit_rate = 5000000;
            c->width    = 1280;
            c->height   = 720;
            c->time_base = (AVRational){ 1, 60 };
            ost->st->time_base = (AVRational){ 1, 19200 };
            c->time_base       = ost->st->time_base;
            
            //c->gop_size      = 12; /* emit one intra frame every twelve frames at most */
            //c->pix_fmt       = STREAM_PIX_FMT;
            break;

Все равно информацию о времени предоставить в сам Mp4 контейнер

#11
(Правка: 18:40) 18:07, 12 янв. 2021

MAMOHT-92
>не уверен на 100%, есть ли в sps/pps какая-то информация о фреймрейте, но вроде я этого не помню
В коде AMF кодека есть строчки:
    amf_pts start_time = amf_high_precision_clock();
    amf_surfaceIn->SetProperty(START_TIME_PROPERTY, start_time);

далее идет собственно обработка фрейма:
    res = amf_encoder->SubmitInput(amf_surfaceIn);

Это явно запись текущего времени, но как она записывается в пакет я не знаю. Вроде по описанию там действительно нет для этого места. Второй звоночек - VLC такой файл не играет а FFmpeg эту информацию игнорирует. Может это какое-то новое расширение стандарта - я не знаю.

>библиотека занимающаяся (de)muxing в ffmpeg - это libavformat.

Что бы ее собрать на Винде я потратил весь день. Там геморрой еще тот. В результате получил несколько библиотек, но они не линкуются с проектом на VS. Из-за чего - х.з. Я не пойму почему этого монстра давно не портировали в VS - все же это самая ходовая платформа разработчиков. Лень, снобизм или проблема авторских прав? Скорее последнее, поскольку использование этих библиотек сопровождается кучей условий. Короче FFmpeg это решение для больших дядей (они заплатят) или для конечного юзера. Но использовать ее в коммерческом проекте средней руки весьма проблематично.

#12
(Правка: 19:37) 19:31, 12 янв. 2021

san
> В коде AMF кодека есть строчки:
> amf_pts start_time = amf_high_precision_clock();
> amf_surfaceIn->SetProperty(START_TIME_PROPERTY, start_time);
еще раз:

MAMOHT-92
> Более того, если ты будешь работать уже с энкодерами, то работа со временем
> станет обязательной, ибо от корректно заданного timestamp и timebase зависит
> соблюдение bitrate. Иначе ты получишь перешакаленное или недожатое видео в
> лучшем случае.
ты не можешь не задавать timestamp для кадра и его длительность(или фреймрейт вцелом) потому что необходим контроль битрейта. pts - это presentation time stamp - время показа кадра, оно может отличаться от dts - decoded timestamp потому что есть B-frame, которые имеют зависимости от предыдущих и последующих кадров. В самом h264 бинарном потоке нет таймстемпов под каждый кадр, им некуда писаться.
Итак тебе нужно:
1)разобраться что такое pts,  dts, timebase, как оно используется (де)кодерами и (де)муксерами
2)почитать про что такое nal uint и какие они бывают, проще начать с h264, и как они могут храниться (AnnexB (разделители) и  AVCC(запись перед ними их размера) )
3)разобраться с libavformat , ffmpeg собирается даже под андроид и одним батником (у нас в проекта ffmpeg использовался, лицензия позволяет, проект стартап, бюджет мелкий).
  Возможно у тебя проблема с линковкой и си конвенцией в с++ коде.
4)"Я не пойму почему этого монстра давно не портировали в VS " научись работе с cmake, через него можно указывать разные тулчейны и делать кросс компиляцию, под тот же самый андроид.


Вроде как, пару лет назад добавили в ffmpeg поддержку нативных (де)кодеров и они сносно работают, вполне возможно тебе больше нет необходимости делать то, что ты делаешь сейчас, а можно обойтись очень высокоуровневым апи.


Если ты хочешь использовать аппаратные декодеры, то придеться подразобраться, хотя бы немного с предметной областью, иначе результат будет печальный, даже если будет работать.

#13
20:03, 12 янв. 2021

MAMOHT-92
> Итак тебе нужно:
> 1)разобраться что такое pts,  dts, timebase, как оно используется (де)кодерами и (де)муксерами

Я не курсовой проект пишу и не диссертацию делаю. Все что мне нужно - это понять (и устранить причину) почему h264 файл аппаратно созданный на AMD с помощью библиотеки AMF (родной для AMD) при преобразовании его в mp4 играется со скоростью создания потока, а не с фиксированной скоростью заданной в MP4V2 (30 fps).  Дело не в MP4V поскольку такой же файл но полученный с помощью Nvidia Encoder играется с нормальной скоростью. Разница явно в h264.

FFmpeg создает mp4 файлы которые воспроизводятся одинаково на обоих платформах но я не готов положить несколько недель на исследования этого монстра что бы вычленить из него функцию создания заголовка mp4.
Кроме того, использование его в коммерческих проектах обставлено рядом условий. Я не для себя одного программу делаю и налетать на иски о нарушении авторских прав не хочу.

Если ты уже в теме, то я могу выложить исходные файлы h264 созданные на AMD и Nvidia и mp4 которые из них получились.

#14
21:02, 12 янв. 2021

Хорошо, можно было бы обойтись одним ffmpeg и заюзать его апи в стиле, открой файл на запись, и периодически вот тебе rgb картинки, отдай мне закодированные данные, и не влезая в их кишки тут же отдавать его же демуксеру, но:

> Кроме того, использование его в коммерческих проектах обставлено рядом условий.

я даже не знаю что тебе предложить, чтобы и использовать хардварные декодеры самому, контролируя весь процесс и при этом не влезать в мат часть. Ведь в чем профит от использования NVEnc -ты тонко настраиваешь энкодер, затем он с отличной скоростью молотит тебе данные, которые ты как хочешь ему отдаешь, более того, картинку на чтение ты ему можешь отдавать из GPU памяти, в которую ты рендеришь своим приложением через dx/opengl.

Страницы: 1 2 Следующая »
ПрограммированиеФорумОбщее