muxer.cpp revision 377b2ec9a2885f9b6405b07ba900a9e3f4349c38
1fc9afba35492257e5e80a36b0765ff035908bb6dztenghui/*
2fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * Copyright (C) 2013 The Android Open Source Project
3fc9afba35492257e5e80a36b0765ff035908bb6dztenghui *
4fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * Licensed under the Apache License, Version 2.0 (the "License");
5fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * you may not use this file except in compliance with the License.
6fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * You may obtain a copy of the License at
7fc9afba35492257e5e80a36b0765ff035908bb6dztenghui *
8fc9afba35492257e5e80a36b0765ff035908bb6dztenghui *      http://www.apache.org/licenses/LICENSE-2.0
9fc9afba35492257e5e80a36b0765ff035908bb6dztenghui *
10fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * Unless required by applicable law or agreed to in writing, software
11fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * distributed under the License is distributed on an "AS IS" BASIS,
12fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * See the License for the specific language governing permissions and
14fc9afba35492257e5e80a36b0765ff035908bb6dztenghui * limitations under the License.
15fc9afba35492257e5e80a36b0765ff035908bb6dztenghui */
16fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
17fc9afba35492257e5e80a36b0765ff035908bb6dztenghui//#define LOG_NDEBUG 0
18fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#define LOG_TAG "muxer"
19377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT#include <inttypes.h>
20fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <utils/Log.h>
21fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
22fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <binder/ProcessState.h>
23fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/foundation/ABuffer.h>
24fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/foundation/ADebug.h>
25fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/foundation/ALooper.h>
26fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/foundation/AMessage.h>
27fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/foundation/AString.h>
28fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/DataSource.h>
29fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/MediaCodec.h>
30fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/MediaDefs.h>
31fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/MediaMuxer.h>
32fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/MetaData.h>
33fc9afba35492257e5e80a36b0765ff035908bb6dztenghui#include <media/stagefright/NuMediaExtractor.h>
34fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
35fc9afba35492257e5e80a36b0765ff035908bb6dztenghuistatic void usage(const char *me) {
36fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    fprintf(stderr, "usage: %s [-a] [-v] [-s <trim start time>]"
37fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                    " [-e <trim end time>] [-o <output file>]"
38fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                    " <input video file>\n", me);
39fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    fprintf(stderr, "       -h help\n");
40fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    fprintf(stderr, "       -a use audio\n");
41fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    fprintf(stderr, "       -v use video\n");
42fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    fprintf(stderr, "       -s Time in milli-seconds when the trim should start\n");
43fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    fprintf(stderr, "       -e Time in milli-seconds when the trim should end\n");
44fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    fprintf(stderr, "       -o output file name. Default is /sdcard/muxeroutput.mp4\n");
45fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
46fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    exit(1);
47fc9afba35492257e5e80a36b0765ff035908bb6dztenghui}
48fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
49fc9afba35492257e5e80a36b0765ff035908bb6dztenghuiusing namespace android;
50fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
51fc9afba35492257e5e80a36b0765ff035908bb6dztenghuistatic int muxing(
52fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        const android::sp<android::ALooper> &looper,
53fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        const char *path,
54fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        bool useAudio,
55fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        bool useVideo,
56fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        const char *outputFileName,
57fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        bool enableTrim,
58fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        int trimStartTimeMs,
5911287471298193ff51ffb429686f5d63a84a621bztenghui        int trimEndTimeMs,
6011287471298193ff51ffb429686f5d63a84a621bztenghui        int rotationDegrees) {
61fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    sp<NuMediaExtractor> extractor = new NuMediaExtractor;
62fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    if (extractor->setDataSource(path) != OK) {
63fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        fprintf(stderr, "unable to instantiate extractor. %s\n", path);
64fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        return 1;
65fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
66fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
67fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    if (outputFileName == NULL) {
68fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        outputFileName = "/sdcard/muxeroutput.mp4";
69fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
70fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
71fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    ALOGV("input file %s, output file %s", path, outputFileName);
72fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    ALOGV("useAudio %d, useVideo %d", useAudio, useVideo);
73fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
74afde4e56566af19b36f1fe5e7aa7f226bf1703ddztenghui    sp<MediaMuxer> muxer = new MediaMuxer(outputFileName,
75afde4e56566af19b36f1fe5e7aa7f226bf1703ddztenghui                                          MediaMuxer::OUTPUT_FORMAT_MPEG_4);
76fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
77fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    size_t trackCount = extractor->countTracks();
78fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    // Map the extractor's track index to the muxer's track index.
79fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    KeyedVector<size_t, ssize_t> trackIndexMap;
80fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    size_t bufferSize = 1 * 1024 * 1024;  // default buffer size is 1MB.
81fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
82fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    bool haveAudio = false;
83fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    bool haveVideo = false;
84fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
85fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int64_t trimStartTimeUs = trimStartTimeMs * 1000;
86fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int64_t trimEndTimeUs = trimEndTimeMs * 1000;
87fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    bool trimStarted = false;
88fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int64_t trimOffsetTimeUs = 0;
89fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
90fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    for (size_t i = 0; i < trackCount; ++i) {
91fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        sp<AMessage> format;
92fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        status_t err = extractor->getTrackFormat(i, &format);
93fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        CHECK_EQ(err, (status_t)OK);
94fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        ALOGV("extractor getTrackFormat: %s", format->debugString().c_str());
95fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
96fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        AString mime;
97fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        CHECK(format->findString("mime", &mime));
98fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
99fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
100fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
101fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
102fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        if (useAudio && !haveAudio && isAudio) {
103fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            haveAudio = true;
104fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        } else if (useVideo && !haveVideo && isVideo) {
105fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            haveVideo = true;
106fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        } else {
107fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            continue;
108fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        }
109fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
110fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        if (isVideo) {
111fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            int width , height;
112fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            CHECK(format->findInt32("width", &width));
113fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            CHECK(format->findInt32("height", &height));
114fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            bufferSize = width * height * 4;  // Assuming it is maximally 4BPP
115fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        }
116fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
117fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        int64_t duration;
118fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        CHECK(format->findInt64("durationUs", &duration));
119fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
120fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        // Since we got the duration now, correct the start time.
121fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        if (enableTrim) {
122fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            if (trimStartTimeUs > duration) {
123fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                fprintf(stderr, "Warning: trimStartTimeUs > duration,"
124fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                                " reset to 0\n");
125fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                trimStartTimeUs = 0;
126fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
127fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        }
128fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
129fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        ALOGV("selecting track %d", i);
130fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
131fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        err = extractor->selectTrack(i);
132fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        CHECK_EQ(err, (status_t)OK);
133fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
134fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        ssize_t newTrackIndex = muxer->addTrack(format);
135fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        CHECK_GE(newTrackIndex, 0);
136fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        trackIndexMap.add(i, newTrackIndex);
137fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
138fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
139fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int64_t muxerStartTimeUs = ALooper::GetNowUs();
140fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
141fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    bool sawInputEOS = false;
142fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
143fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    size_t trackIndex = -1;
144fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    sp<ABuffer> newBuffer = new ABuffer(bufferSize);
145fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
14611287471298193ff51ffb429686f5d63a84a621bztenghui    muxer->setOrientationHint(rotationDegrees);
147fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    muxer->start();
148fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
149fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    while (!sawInputEOS) {
150fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        status_t err = extractor->getSampleTrackIndex(&trackIndex);
151fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        if (err != OK) {
152fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            ALOGV("saw input eos, err %d", err);
153fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            sawInputEOS = true;
154fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            break;
155fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        } else {
156fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            err = extractor->readSampleData(newBuffer);
157fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            CHECK_EQ(err, (status_t)OK);
158fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
159fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            int64_t timeUs;
160fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            err = extractor->getSampleTime(&timeUs);
161fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            CHECK_EQ(err, (status_t)OK);
162fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
163fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            sp<MetaData> meta;
164fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            err = extractor->getSampleMeta(&meta);
165fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            CHECK_EQ(err, (status_t)OK);
166fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
167fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            uint32_t sampleFlags = 0;
168fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            int32_t val;
169fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            if (meta->findInt32(kKeyIsSyncFrame, &val) && val != 0) {
170fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                // We only support BUFFER_FLAG_SYNCFRAME in the flag for now.
171fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                sampleFlags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
172fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
173fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                // We turn on trimming at the sync frame.
174fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                if (enableTrim && timeUs > trimStartTimeUs &&
175fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                    timeUs <= trimEndTimeUs) {
176fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                    if (trimStarted == false) {
177fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                        trimOffsetTimeUs = timeUs;
178fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                    }
179fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                    trimStarted = true;
180fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                }
181fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
182fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            // Trim can end at any non-sync frame.
183fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            if (enableTrim && timeUs > trimEndTimeUs) {
184fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                trimStarted = false;
185fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
186fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
187fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            if (!enableTrim || (enableTrim && trimStarted)) {
188fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                err = muxer->writeSampleData(newBuffer,
189fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                                             trackIndexMap.valueFor(trackIndex),
190fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                                             timeUs - trimOffsetTimeUs, sampleFlags);
191fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
192fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
193fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            extractor->advance();
194fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        }
195fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
196fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
197fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    muxer->stop();
198fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    newBuffer.clear();
199fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    trackIndexMap.clear();
200fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
201fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int64_t elapsedTimeUs = ALooper::GetNowUs() - muxerStartTimeUs;
202377b2ec9a2885f9b6405b07ba900a9e3f4349c38Kévin PETIT    fprintf(stderr, "SUCCESS: muxer generate the video in %" PRId64 " ms\n",
203fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            elapsedTimeUs / 1000);
204fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
205fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    return 0;
206fc9afba35492257e5e80a36b0765ff035908bb6dztenghui}
207fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
208fc9afba35492257e5e80a36b0765ff035908bb6dztenghuiint main(int argc, char **argv) {
209fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    const char *me = argv[0];
210fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
211fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    bool useAudio = false;
212fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    bool useVideo = false;
213fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    char *outputFileName = NULL;
214fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int trimStartTimeMs = -1;
215fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int trimEndTimeMs = -1;
21611287471298193ff51ffb429686f5d63a84a621bztenghui    int rotationDegrees = 0;
217fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    // When trimStartTimeMs and trimEndTimeMs seems valid, we turn this switch
218fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    // to true.
219fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    bool enableTrim = false;
220fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
221fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int res;
22211287471298193ff51ffb429686f5d63a84a621bztenghui    while ((res = getopt(argc, argv, "h?avo:s:e:r:")) >= 0) {
223fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        switch (res) {
224fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            case 'a':
225fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            {
226fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                useAudio = true;
227fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                break;
228fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
229fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
230fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            case 'v':
231fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            {
232fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                useVideo = true;
233fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                break;
234fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
235fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
236fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            case 'o':
237fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            {
238fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                outputFileName = optarg;
239fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                break;
240fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
241fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
242fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            case 's':
243fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            {
244fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                trimStartTimeMs = atoi(optarg);
245fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                break;
246fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
247fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
248fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            case 'e':
249fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            {
250fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                trimEndTimeMs = atoi(optarg);
251fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                break;
252fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
253fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
25411287471298193ff51ffb429686f5d63a84a621bztenghui            case 'r':
25511287471298193ff51ffb429686f5d63a84a621bztenghui            {
25611287471298193ff51ffb429686f5d63a84a621bztenghui                rotationDegrees = atoi(optarg);
25711287471298193ff51ffb429686f5d63a84a621bztenghui                break;
25811287471298193ff51ffb429686f5d63a84a621bztenghui            }
25911287471298193ff51ffb429686f5d63a84a621bztenghui
260fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            case '?':
261fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            case 'h':
262fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            default:
263fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            {
264fc9afba35492257e5e80a36b0765ff035908bb6dztenghui                usage(me);
265fc9afba35492257e5e80a36b0765ff035908bb6dztenghui            }
266fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        }
267fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
268fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
269fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    argc -= optind;
270fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    argv += optind;
271fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
272fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    if (argc != 1) {
273fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        usage(me);
274fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
275fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
276fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    if (trimStartTimeMs < 0 || trimEndTimeMs < 0) {
277fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        // If no input on either 's' or 'e', or they are obviously wrong input,
278fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        // then turn off trimming.
279fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        ALOGV("Trimming is disabled, copying the whole length video.");
280fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        enableTrim = false;
281fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    } else if (trimStartTimeMs > trimEndTimeMs) {
282fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        fprintf(stderr, "ERROR: start time is bigger\n");
283fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        return 1;
284fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    } else {
285fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        enableTrim = true;
286fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
287fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
288fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    if (!useAudio && !useVideo) {
289fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        fprintf(stderr, "ERROR: Missing both -a and -v, no track to mux then.\n");
290fc9afba35492257e5e80a36b0765ff035908bb6dztenghui        return 1;
291fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    }
292fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    ProcessState::self()->startThreadPool();
293fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
294fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    // Make sure setDataSource() works.
295fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    DataSource::RegisterDefaultSniffers();
296fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
297fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    sp<ALooper> looper = new ALooper;
298fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    looper->start();
299fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
300fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    int result = muxing(looper, argv[0], useAudio, useVideo, outputFileName,
30111287471298193ff51ffb429686f5d63a84a621bztenghui                        enableTrim, trimStartTimeMs, trimEndTimeMs, rotationDegrees);
302fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
303fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    looper->stop();
304fc9afba35492257e5e80a36b0765ff035908bb6dztenghui
305fc9afba35492257e5e80a36b0765ff035908bb6dztenghui    return result;
306fc9afba35492257e5e80a36b0765ff035908bb6dztenghui}
307