2014-12-04 3 views
3

Я хочу использовать mp4v-es вместо avc на некоторых устройствах. Датчик работает нормально с использованием АВК, но когда я заменить его MP4V-х годов, отчеты Muxer:Android: Как использовать MediaMuxer с видео/mp4v-es вместо видео/avc?

E/MPEG4Writer(12517): Missing codec specific data 

как в MediaMuxer error "Failed to stop the muxer", и видео не могут быть воспроизведены. Разница заключается в том, что я добавляю правильный трек/формат с мультиплексором, не получая никакой ошибки:

...else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { 
      MediaFormat newFormat = encoder.getOutputFormat(); 
      mTrackIndex[encID] = mMuxer.addTrack(newFormat); 

Есть ли разница в обработке MP4V-эс по сравнению с АВК? Одно упоминание, я просто пропускаю «bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG», когда это происходит, так как для avc это не было необходимо. Спасибо.

+0

Имеет ли newFormat csd-0 и csd-1? – Marlon

+1

@Marlon: newFormat: {height = 720, mime = video/mp4v-es, csd-0 = java.nio.ByteArrayBuffer [position = 0, limit = 30, capacity = 30], what = 1869968451, width = 1280} и csd-0: 000001B006000001B58913000001000000012000C48881F4528045A1463F. csd-1 нет, но я думаю, что он появляется только для H264. – user1592546

+0

http://stackoverflow.com/questions/21341169/mediamuxer-fails-to-stop-if-csd-1-not-exist похоже, что csd-1 может потребоваться – Marlon

ответ

2

Как показал Ганеш, к сожалению, сейчас это невозможно, без изменения источника платформы.

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

Как обнаружил Ганеш, логика переназначения ключей MediaFormat во внутренний формат, по-видимому, не позволяет обрабатывать специфические данные кодека для любого другого видеокодека, чем H264. Испытуемый модификация, которая устраняет эту проблему следующим образом:

diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp 
index 25afc5b..304fe59 100644 
--- a/media/libstagefright/Utils.cpp 
+++ b/media/libstagefright/Utils.cpp 
@@ -549,14 +549,14 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { 
    // reassemble the csd data into its original form 
    sp<ABuffer> csd0; 
    if (msg->findBuffer("csd-0", &csd0)) { 
-  if (mime.startsWith("video/")) { // do we need to be stricter than this? 
+  if (mime == MEDIA_MIMETYPE_VIDEO_AVC) { 
      sp<ABuffer> csd1; 
      if (msg->findBuffer("csd-1", &csd1)) { 
       char avcc[1024]; // that oughta be enough, right? 
       size_t outsize = reassembleAVCC(csd0, csd1, avcc); 
       meta->setData(kKeyAVCC, kKeyAVCC, avcc, outsize); 
      } 
-  } else if (mime.startsWith("audio/")) { 
+  } else if (mime == MEDIA_MIMETYPE_AUDIO_AAC || mime == MEDIA_MIMETYPE_VIDEO_MPEG4) { 
      int csd0size = csd0->size(); 
      char esds[csd0size + 31]; 
      reassembleESDS(csd0, esds); 

Во-вторых, вместо передачи кодеков конкретные данные, csd-0 в MediaFormat, можно в принципе пройти один и тот же буфер (с набором MediaCodec.BUFFER_FLAG_CODEC_CONFIG флага) в MediaMuxer.writeSampleData.Такой подход не работает в настоящее время, так как этот метод не проверяет флаг кодека конфигурации на всех - это может быть исправлен с этой модификацией:

diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp 
index c7c6f34..d612e01 100644 
--- a/media/libstagefright/MediaMuxer.cpp 
+++ b/media/libstagefright/MediaMuxer.cpp 
@@ -193,6 +193,9 @@ status_t MediaMuxer::writeSampleData(const sp<ABuffer> &buffer, size_t trackInde 
    if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME) { 
     sampleMetaData->setInt32(kKeyIsSyncFrame, true); 
    } 
+ if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) { 
+  sampleMetaData->setInt32(kKeyIsCodecConfig, true); 
+ } 

    sp<MediaAdapter> currentTrack = mTrackList[trackIndex]; 
    // This pushBuffer will wait until the mediaBuffer is consumed. 

Насколько я могу видеть, что нет никакого способа мультиплексирования MPEG4 видео с MediaMuxer прямо сейчас, используя общедоступный API, без изменения источника платформы. Учитывая проблемы в Utils.cpp выше, вы не можете мультиплексировать какой-либо видеоформат, требующий конкретных данных кодека, за исключением H264. Если VP8 является опцией, вы можете мультиплексировать это в файлы webm (вместе с аудио vorbis), но аппаратные кодеры для VP8, вероятно, гораздо менее распространены, чем аппаратные кодеры для MPEG4.

+0

Эта проблема была опубликована на сайте http://b.android.com/90138, а исправление было отправлено на https://android-review.googlesource.com/120945. – mstorsjo

+0

Благодарим за сообщение об этой проблеме и исправление ее в основное дерево. – Ganesh

+0

Ну, исправление еще не слито. Я действительно нашел 2 разных изменения, ожидающих обзора, которые делают почти то же самое, которые были представлены другими людьми (казалось бы, не связанными с этим сообщением здесь), но никто еще не объединился или даже не прокомментировал это. – mstorsjo

2

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

фон:

Когда encoder заканчивает кодирование, первый буфер будет иметь csd информации, которая, как правило, с меткой OMX_BUFFERFLAG_CODECCONFIG флага. Когда такой буфер возвращается в MediaCodec, он должен хранить то же, что и csd-0, в MediaCodec::amendOutputFormatWithCodecSpecificData.

Теперь, когда этот буфер отдается MediaMuxer, то же обрабатывается как часть addTrack, в котором convertMessageToMetadata вызывается. Если вы ссылаетесь на их реализацию, мы можем заметить, что только AVC обрабатывается для video и по умолчанию audio для ESDS.

EDIT:

Вот моя рекомендация состоит в том, чтобы изменить эту line, как показано ниже и попробовать эксперимент

} 
if (mime.startsWith("audio/") || (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { 

С этим изменением, я чувствую, что это должно работать на MPEG4 видеодорожкой также. Изменение заключается в преобразовании else if в if, поскольку предыдущая проверка для video также попытается обработать данные, но только для AVC.

+0

Не будет код в строке 552: «if (mime.startsWith (« video/»)) {« получить все видео буферы? Во всяком случае, мне нужно будет экспортировать mp4v-es с использованием общедоступного API MediaCodec (чтобы я мог манипулировать содержимым буфера по мере необходимости), но не прибегать к jni и собственному коду. – user1592546

+0

@ user1592546..Да, вы правы. Мы можем преодолеть это, удалив 'else' в' else if', чтобы было 2 проверки. Чтобы оптимизировать это, для первой проверки «видео» мы могли бы добавить еще одну часть, чтобы проверить, является ли тип «MIME» 'AVC' или нет. См. Мой отредактированный ответ выше. – Ganesh

+1

Я приму решение mstorsjo, для полноты, дополнительной ссылки и предоставления ссылки на полное решение. Во всяком случае, этот ответ дал более глубокое понимание этой проблемы и ценится. – user1592546