Отправлять периодические метаданные в фрагментированном живом потоке MP4? - PullRequest
0 голосов
/ 14 января 2019

Как следует из темы, мне интересно, можно ли периодически отправлять метаданные о содержимом потока в фрагментированном живом потоке MP4.

Я использую следующую команду (1) для получения фрагментированного MP4:

ffmpeg -i rtsp://admin:12345@192.168.0.157 -c:v copy -an -movflags empty_moov+omit_tfhd_offset+frag_keyframe+default_base_moof -f mp4 ...

Моя основная программа читает фрагменты этой команды из стандартного вывода или из сокета (домена unix) и получает:

ftyp
moov
moof
mdat
moof
mdat
moof
mdat 
...

Итак, первые фрагменты, которые я получаю, это ftyp и moov , которые являются метаданными и описывают содержимое потока.

Теперь клиентская программа позднее подключается к основной программе . Проблема в том, что на этом этапе фрагменты ftype и moov давно исчезли.

Есть ли способ (= опция команды ffmpeg) сделать эту работу похожей на MPEGTS (известный как транспортный поток mpeg) и периодически пересылать метаданные с потоком? Например:

ftyp
moov
moof
mdat
moof
mdat
moof
mdat 
ftyp
moov
moof
mdat
moof
mdat
moof
mdat 
...

.. или мой единственный вариант - кэшировать пакеты ftyp и moov в моей основной программе и повторно отправлять их клиенту программа когда запрашивает поток?

Связанная ссылка: Что такое Fragmented mp4 (fMP4)? Чем он отличается от обычного mp4?

Кэширование и повторная отправка ftyp и moov каждый раз, когда новый клиент подключается, тоже не так просто ... так как он каким-то образом нарушает поток (по крайней мере, расширения MSE в браузере этого не делают нравится такой поток). Кажется, в пакетах moof есть много порядковых номеров и прочего, которые следует изменить. (+)

Другой вариант - пропустить поток через другой процесс FFmpeg, который выполняет повторное смешивание (и исправляет moof пакетов). Ситуация усложняется еще и тем, что команда (1) не дает четко разделенных ftyp , moov , moof и т. Д.

Любые мысли / решения приветствуются.

EDIT : в отношении (+) MSE, похоже, испытывает проблемы при воспроизведении фрагментированного MP4 с пробелами: https://bugs.chromium.org/p/chromium/issues/detail?id=516114

Ответы [ 2 ]

0 голосов
/ 22 января 2019

Мне наконец-то удалось передать фрагментированный MP4 в расширения MSE для браузера.

Если вы начнете кормить расширения MSE пакетами moof и mdat , которые не пришли сразу после оригинальных ftyp и moov тогда ..

.. самый первый пакет moof , который входит в расширение MSE, должен быть пакетом moof , для которого установлен специальный флаг first_sample_flags_preset (см. Спецификации ISO / IEC 14496-12: 2012 (E) для получения дополнительной информации)

.. в противном случае MSE во всех популярных браузерах зависают и воспроизведение видео не происходит (кстати, moof порядковые номера, начинающиеся с> 1, не создают никаких проблем).

Этот пакет на python был очень полезен для анализа: https://github.com/beardypig/pymp4

Чтобы установить этот флаг, в этом ответе предусмотрены функции JavaScript на стороне клиента.

Используйте функцию getBox , чтобы узнать тип коробки ( ftyp , moov , moof и т. Д.).

Для блоков moof примените функцию findFirstSampleFlag , чтобы увидеть, имеет ли поле moof first_sample_flags_preset .

function toInt(arr, index) { // From bytes to big-endian 32-bit integer.  Input: Uint8Array, index
    var dv = new DataView(arr.buffer, 0);
    return dv.getInt32(index, false); // big endian
}

function toString(arr, fr, to) { // From bytes to string.  Input: Uint8Array, start index, stop index.
    return String.fromCharCode.apply(null, arr.slice(fr,to));
}

function getBox(arr, i) { // input Uint8Array, start index
    return [toInt(arr, i), toString(arr, i+4, i+8)]
}

function getSubBox(arr, box_name) { // input Uint8Array, box name
    var i = 0;
    res = getBox(arr, i);
    main_length = res[0]; name = res[1]; // this boxes length and name
    i = i + 8;

    var sub_box = null;

    while (i < main_length) {
        res = getBox(arr, i);
        l = res[0]; name = res[1];

        if (box_name == name) {
            sub_box = arr.slice(i, i+l)
        }
        i = i + l;
    }
    return sub_box;
}

function findFirstSampleFlag(arr) { // input Uint8Array
    // [moof [mfhd] [traf [tfhd] [tfdt] [trun]]]

    var traf = getSubBox(arr, "traf");
    if (traf==null) { return false; }

    var trun = getSubBox(traf, "trun");
    if (trun==null) { return false; }

    // ISO/IEC 14496-12:2012(E) .. pages 5 and 57
    // bytes: (size 4), (name 4), (version 1 + tr_flags 3)
    var flags = trun.slice(10,13); // console.log(flags);
    f = flags[1] & 4; // console.log(f);
    return f == 4;
}
0 голосов
/ 14 января 2019

ftyp / moov образует так называемый «фрагмент инициализации» и должен записываться только в MSE при изменении потоков. Обычно это делается путем включения URL-адреса init в манифест, и задача игроков - запрашивать его при присоединении к потоку.

...