Ошибка в addTrack () при попытке мультиплексировать аудио и видео - PullRequest
0 голосов
/ 12 июня 2018

Я разрабатываю собственное приложение для Android, в котором записываю видеопоток экрана (кодируя его с собственной библиотекой AMediaCodec в video/avc) и смешиваю его с аудиодорожкой AAC / audio/mp4a-latm.Мой код прекрасно работает на нескольких устройствах, но у меня возникли проблемы с некоторыми устройствами (Huawei P8 и P10 lite, работающие под управлением Android 6.0.0 и 7.0 соответственно, и Nexus 5 под управлением Android 6.0.1).Проблема в том, что всякий раз, когда я пытаюсь добавить второй трек в мультиплексор (независимо от порядка их добавления), он терпит неудачу , возвращая -10000 код ошибки.

Я упростил проблему, пытаясь просто смешать аудио и видео файл вместе;результаты одинаковы.В этой упрощенной версии я использую два AMediaExtractor для получения аудио и видео форматов для настройки AMediaMuxer, но когда я добавляю вторую дорожку, я все равно получаю ошибку.Вот код:

const auto videoSample = "videosample.mp4";
const auto audioSample = "audiosample.aac";
const auto filePath = "muxed_file.mp4"

auto* extractorV = AMediaExtractor_new();
AMediaExtractor_setDataSource(extractorV, videoSample);
AMediaExtractor_selectTrack(extractorV, 0U); // here I take care to select the right "video/avc" track
auto* videoFormat = AMediaExtractor_getTrackFormat(extractorV, 0U);

auto* extractorA = AMediaExtractor_new();
AMediaExtractor_setDataSource(extractorA, audioSample);
AMediaExtractor_selectTrack(extractorA, 0U); // here I take care to select the right "mp4a-latm" track
auto* audioFormat = AMediaExtractor_getTrackFormat(extractorA, 0U);

auto fd = open(filePath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
auto* muxer = AMediaMuxer_new(fd, AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4);
auto videoTrack = AMediaMuxer_addTrack(muxer, videoFormat); // the operation succeeds: videoTrack is 0
auto audioTrack = AMediaMuxer_addTrack(muxer, audioFormat); // error: audioTrack is -10000

AMediaExtractor_seekTo(extractorV, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
AMediaExtractor_seekTo(extractorA, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);

AMediaMuxer_start(muxer);

Что-то не так с моим кодом?Это то, что не должно работать на Android до 8 или это чистое совпадение?Я прочитал много постов (особенно @fadden) здесь, на SO, но я не могу понять это.

Позвольте мне дать вам некоторый контекст:

  • ошибка не зависит от порядка добавления двух дорожек: всегда будет второй AMediaMuxer_addTrack() сбой
  • аудио и видео дорожки должны быть в порядке: когда яmux только одна из дорожек, все работает хорошо даже на Huaweis и Nexus 5, я получаю правильные выходные файлы, как с аудио, так и с видео дорожкой
  • Я пытался переместить вызовы AMediaExtractor_seekTo() надругие позиции, но безуспешно
  • тот же код отлично работает на других устройствах (OnePlus 5 и Nokia 7 plus, оба работают под управлением Android> = 8.0)

Просто для полноты, этокод, который я позже использую для получения выходного файла mp4:

AMediaMuxer_start(muxer);

// mux the VIDEO track
std::array<uint8_t, 256U * 1024U> videoBuf;
AMediaCodecBufferInfo videoBufInfo{};
videoBufInfo.flags = AMediaExtractor_getSampleFlags(extractorV);
bool videoEos{};
while (!videoEos) {
    auto ts = AMediaExtractor_getSampleTime(extractorV);
    videoBufInfo.presentationTimeUs = std::max(videoBufInfo.presentationTimeUs, ts);
    videoBufInfo.size = AMediaExtractor_readSampleData(extractorV, videoBuf.data(), videoBuf.size());
    if(videoBufInfo.presentationTimeUs == -1 || videoBufInfo.size < 0) {
        videoEos = true;
    } else {
        AMediaMuxer_writeSampleData(muxer, videoTrack, videoBuf.data(), &videoBufInfo);
        AMediaExtractor_advance(extractorV);
    }
}

// mux the audio track
std::array<uint8_t, 256U * 1024U> audioBuf;
AMediaCodecBufferInfo audioBufInfo{};
audioBufInfo.flags = AMediaExtractor_getSampleFlags(extractorA);
bool audioEos{};
while (!audioEos) {
    audioBufInfo.size = AMediaExtractor_readSampleData(extractorA, audioBuf.data(), audioBuf.size());
    if(audioBufInfo.size < 0) {
        audioEos = true;
    } else {
        audioBufInfo.presentationTimeUs = AMediaExtractor_getSampleTime(extractorA);
        AMediaMuxer_writeSampleData(muxer, audioTrack, audioBuf.data(), &audioBufInfo);
        AMediaExtractor_advance(extractorA);
    }
}

AMediaMuxer_stop(muxer);
AMediaMuxer_delete(muxer);
close(fd);
AMediaFormat_delete(audioFormat);
AMediaExtractor_delete(extractorA);
AMediaFormat_delete(videoFormat);
AMediaExtractor_delete(extractorV);
...