addTrack()尝试复用音频和视频时出错

时间:2018-06-12 10:44:09

标签: android c++ android-ndk mediacodec mediamuxer

我正在开发一个Android原生应用,用于记录屏幕视频流(使用原生AMediaCodec库对其进行编码为video/avc),然后将其与AAC / audio/mp4a-latm进行复用音轨。我的代码在几个设备上运行得很好,但是我遇到了一些设备的问题(华为P8和P10 lite,分别运行Android 6.0.0和7.0,运行Android 6.0.1的Nexus 5)。问题是,每当我尝试将第二首曲目添加到多路复用器时(无论我添加的顺序如何),失败会返回-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);

我的代码有问题吗?它是不是应该在8之前在Android上运行的东西,或者它是纯粹的巧合?我已经在SO上阅读了很多帖子(特别是@fadden),但我无法弄明白。

让我给你一些背景信息:

  • 失败与我添加两个曲目的顺序无关:它总是第二个AMediaMuxer_addTrack()失败
  • 音频和视频曲目应该没问题:当我只复制其中一首曲目时,一切正常即使在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);

0 个答案:

没有答案