static int muxing( const char *path, bool useAudio, bool useVideo, const char *outputFileName, bool enableTrim, int trimStartTimeMs, int trimEndTimeMs, int rotationDegrees, MediaMuxer::OutputFormat container = MediaMuxer::OUTPUT_FORMAT_MPEG_4) { sp<NuMediaExtractor> extractor = new NuMediaExtractor; if (extractor->setDataSource(NULL /* httpService */, path) != OK) { fprintf(stderr, "unable to instantiate extractor. %s\n", path); return 1; } if (outputFileName == NULL) { outputFileName = "/sdcard/muxeroutput.mp4"; } ALOGV("input file %s, output file %s", path, outputFileName); ALOGV("useAudio %d, useVideo %d", useAudio, useVideo); int fd = open(outputFileName, O_CREAT | O_LARGEFILE | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); if (fd < 0) { ALOGE("couldn't open file"); return fd; } sp<MediaMuxer> muxer = new MediaMuxer(fd, container); close(fd); size_t trackCount = extractor->countTracks(); // Map the extractor's track index to the muxer's track index. KeyedVector<size_t, ssize_t> trackIndexMap; size_t bufferSize = 1 * 1024 * 1024; // default buffer size is 1MB. bool haveAudio = false; bool haveVideo = false; int64_t trimStartTimeUs = trimStartTimeMs * 1000; int64_t trimEndTimeUs = trimEndTimeMs * 1000; bool trimStarted = false; int64_t trimOffsetTimeUs = 0; for (size_t i = 0; i < trackCount; ++i) { sp<AMessage> format; status_t err = extractor->getTrackFormat(i, &format); CHECK_EQ(err, (status_t)OK); ALOGV("extractor getTrackFormat: %s", format->debugString().c_str()); AString mime; CHECK(format->findString("mime", &mime)); bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6); bool isVideo = !strncasecmp(mime.c_str(), "video/", 6); if (useAudio && !haveAudio && isAudio) { haveAudio = true; } else if (useVideo && !haveVideo && isVideo) { haveVideo = true; } else { continue; } if (isVideo) { int width , height; CHECK(format->findInt32("width", &width)); CHECK(format->findInt32("height", &height)); bufferSize = width * height * 4; // Assuming it is maximally 4BPP } int64_t duration; CHECK(format->findInt64("durationUs", &duration)); // Since we got the duration now, correct the start time. if (enableTrim) { if (trimStartTimeUs > duration) { fprintf(stderr, "Warning: trimStartTimeUs > duration," " reset to 0\n"); trimStartTimeUs = 0; } } ALOGV("selecting track %zu", i); err = extractor->selectTrack(i); CHECK_EQ(err, (status_t)OK); ssize_t newTrackIndex = muxer->addTrack(format); if (newTrackIndex < 0) { fprintf(stderr, "%s track (%zu) unsupported by muxer\n", isAudio ? "audio" : "video", i); } else { trackIndexMap.add(i, newTrackIndex); } } int64_t muxerStartTimeUs = ALooper::GetNowUs(); bool sawInputEOS = false; size_t trackIndex = -1; sp<ABuffer> newBuffer = new ABuffer(bufferSize); muxer->setOrientationHint(rotationDegrees); muxer->start(); while (!sawInputEOS) { status_t err = extractor->getSampleTrackIndex(&trackIndex); if (err != OK) { ALOGV("saw input eos, err %d", err); sawInputEOS = true; break; } else if (trackIndexMap.indexOfKey(trackIndex) < 0) { // ALOGV("skipping input from unsupported track %zu", trackIndex); extractor->advance(); continue; } else { // ALOGV("reading sample from track index %zu\n", trackIndex); err = extractor->readSampleData(newBuffer); CHECK_EQ(err, (status_t)OK); int64_t timeUs; err = extractor->getSampleTime(&timeUs); CHECK_EQ(err, (status_t)OK); sp<MetaData> meta; err = extractor->getSampleMeta(&meta); CHECK_EQ(err, (status_t)OK); uint32_t sampleFlags = 0; int32_t val; if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) { // We only support BUFFER_FLAG_SYNCFRAME in the flag for now. sampleFlags |= MediaCodec::BUFFER_FLAG_SYNCFRAME; // We turn on trimming at the sync frame. if (enableTrim && timeUs > trimStartTimeUs && timeUs <= trimEndTimeUs) { if (trimStarted == false) { trimOffsetTimeUs = timeUs; } trimStarted = true; } } // Trim can end at any non-sync frame. if (enableTrim && timeUs > trimEndTimeUs) { trimStarted = false; } if (!enableTrim || (enableTrim && trimStarted)) { err = muxer->writeSampleData(newBuffer, trackIndexMap.valueFor(trackIndex), timeUs - trimOffsetTimeUs, sampleFlags); } extractor->advance(); } } muxer->stop(); newBuffer.clear(); trackIndexMap.clear(); int64_t elapsedTimeUs = ALooper::GetNowUs() - muxerStartTimeUs; fprintf(stderr, "SUCCESS: muxer generate the video in %" PRId64 " ms\n", elapsedTimeUs / 1000); return 0; }