1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "codec"
19 #include <inttypes.h>
20 #include <utils/Log.h>
21
22 #include "SimplePlayer.h"
23
24 #include <binder/IServiceManager.h>
25 #include <binder/ProcessState.h>
26 #include <media/ICrypto.h>
27 #include <media/IMediaHTTPService.h>
28 #include <media/IMediaPlayerService.h>
29 #include <media/stagefright/foundation/ABuffer.h>
30 #include <media/stagefright/foundation/ADebug.h>
31 #include <media/stagefright/foundation/ALooper.h>
32 #include <media/stagefright/foundation/AMessage.h>
33 #include <media/stagefright/foundation/AString.h>
34 #include <media/stagefright/DataSource.h>
35 #include <media/stagefright/MediaCodec.h>
36 #include <media/stagefright/MediaCodecList.h>
37 #include <media/stagefright/MediaDefs.h>
38 #include <media/stagefright/NuMediaExtractor.h>
39 #include <gui/ISurfaceComposer.h>
40 #include <gui/SurfaceComposerClient.h>
41 #include <gui/Surface.h>
42 #include <ui/DisplayInfo.h>
43
usage(const char * me)44 static void usage(const char *me) {
45 fprintf(stderr, "usage: %s [-a] use audio\n"
46 "\t\t[-v] use video\n"
47 "\t\t[-p] playback\n"
48 "\t\t[-S] allocate buffers from a surface\n"
49 "\t\t[-R] render output to surface (enables -S)\n"
50 "\t\t[-T] use render timestamps (enables -R)\n",
51 me);
52 exit(1);
53 }
54
55 namespace android {
56
57 struct CodecState {
58 sp<MediaCodec> mCodec;
59 Vector<sp<ABuffer> > mInBuffers;
60 Vector<sp<ABuffer> > mOutBuffers;
61 bool mSignalledInputEOS;
62 bool mSawOutputEOS;
63 int64_t mNumBuffersDecoded;
64 int64_t mNumBytesDecoded;
65 bool mIsAudio;
66 };
67
68 } // namespace android
69
decode(const android::sp<android::ALooper> & looper,const char * path,bool useAudio,bool useVideo,const android::sp<android::Surface> & surface,bool renderSurface,bool useTimestamp)70 static int decode(
71 const android::sp<android::ALooper> &looper,
72 const char *path,
73 bool useAudio,
74 bool useVideo,
75 const android::sp<android::Surface> &surface,
76 bool renderSurface,
77 bool useTimestamp) {
78 using namespace android;
79
80 static int64_t kTimeout = 500ll;
81
82 sp<NuMediaExtractor> extractor = new NuMediaExtractor;
83 if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
84 fprintf(stderr, "unable to instantiate extractor.\n");
85 return 1;
86 }
87
88 KeyedVector<size_t, CodecState> stateByTrack;
89
90 bool haveAudio = false;
91 bool haveVideo = false;
92 for (size_t i = 0; i < extractor->countTracks(); ++i) {
93 sp<AMessage> format;
94 status_t err = extractor->getTrackFormat(i, &format);
95 CHECK_EQ(err, (status_t)OK);
96
97 AString mime;
98 CHECK(format->findString("mime", &mime));
99
100 bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
101 bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
102
103 if (useAudio && !haveAudio && isAudio) {
104 haveAudio = true;
105 } else if (useVideo && !haveVideo && isVideo) {
106 haveVideo = true;
107 } else {
108 continue;
109 }
110
111 ALOGV("selecting track %zu", i);
112
113 err = extractor->selectTrack(i);
114 CHECK_EQ(err, (status_t)OK);
115
116 CodecState *state =
117 &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
118
119 state->mNumBytesDecoded = 0;
120 state->mNumBuffersDecoded = 0;
121 state->mIsAudio = isAudio;
122
123 state->mCodec = MediaCodec::CreateByType(
124 looper, mime.c_str(), false /* encoder */);
125
126 CHECK(state->mCodec != NULL);
127
128 err = state->mCodec->configure(
129 format, isVideo ? surface : NULL,
130 NULL /* crypto */,
131 0 /* flags */);
132
133 CHECK_EQ(err, (status_t)OK);
134
135 state->mSignalledInputEOS = false;
136 state->mSawOutputEOS = false;
137 }
138
139 CHECK(!stateByTrack.isEmpty());
140
141 int64_t startTimeUs = ALooper::GetNowUs();
142 int64_t startTimeRender = -1;
143
144 for (size_t i = 0; i < stateByTrack.size(); ++i) {
145 CodecState *state = &stateByTrack.editValueAt(i);
146
147 sp<MediaCodec> codec = state->mCodec;
148
149 CHECK_EQ((status_t)OK, codec->start());
150
151 CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
152 CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
153
154 ALOGV("got %zu input and %zu output buffers",
155 state->mInBuffers.size(), state->mOutBuffers.size());
156 }
157
158 bool sawInputEOS = false;
159
160 for (;;) {
161 if (!sawInputEOS) {
162 size_t trackIndex;
163 status_t err = extractor->getSampleTrackIndex(&trackIndex);
164
165 if (err != OK) {
166 ALOGV("saw input eos");
167 sawInputEOS = true;
168 } else {
169 CodecState *state = &stateByTrack.editValueFor(trackIndex);
170
171 size_t index;
172 err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
173
174 if (err == OK) {
175 ALOGV("filling input buffer %zu", index);
176
177 const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index);
178
179 err = extractor->readSampleData(buffer);
180 CHECK_EQ(err, (status_t)OK);
181
182 int64_t timeUs;
183 err = extractor->getSampleTime(&timeUs);
184 CHECK_EQ(err, (status_t)OK);
185
186 uint32_t bufferFlags = 0;
187
188 err = state->mCodec->queueInputBuffer(
189 index,
190 0 /* offset */,
191 buffer->size(),
192 timeUs,
193 bufferFlags);
194
195 CHECK_EQ(err, (status_t)OK);
196
197 extractor->advance();
198 } else {
199 CHECK_EQ(err, -EAGAIN);
200 }
201 }
202 } else {
203 for (size_t i = 0; i < stateByTrack.size(); ++i) {
204 CodecState *state = &stateByTrack.editValueAt(i);
205
206 if (!state->mSignalledInputEOS) {
207 size_t index;
208 status_t err =
209 state->mCodec->dequeueInputBuffer(&index, kTimeout);
210
211 if (err == OK) {
212 ALOGV("signalling input EOS on track %zu", i);
213
214 err = state->mCodec->queueInputBuffer(
215 index,
216 0 /* offset */,
217 0 /* size */,
218 0ll /* timeUs */,
219 MediaCodec::BUFFER_FLAG_EOS);
220
221 CHECK_EQ(err, (status_t)OK);
222
223 state->mSignalledInputEOS = true;
224 } else {
225 CHECK_EQ(err, -EAGAIN);
226 }
227 }
228 }
229 }
230
231 bool sawOutputEOSOnAllTracks = true;
232 for (size_t i = 0; i < stateByTrack.size(); ++i) {
233 CodecState *state = &stateByTrack.editValueAt(i);
234 if (!state->mSawOutputEOS) {
235 sawOutputEOSOnAllTracks = false;
236 break;
237 }
238 }
239
240 if (sawOutputEOSOnAllTracks) {
241 break;
242 }
243
244 for (size_t i = 0; i < stateByTrack.size(); ++i) {
245 CodecState *state = &stateByTrack.editValueAt(i);
246
247 if (state->mSawOutputEOS) {
248 continue;
249 }
250
251 size_t index;
252 size_t offset;
253 size_t size;
254 int64_t presentationTimeUs;
255 uint32_t flags;
256 status_t err = state->mCodec->dequeueOutputBuffer(
257 &index, &offset, &size, &presentationTimeUs, &flags,
258 kTimeout);
259
260 if (err == OK) {
261 ALOGV("draining output buffer %zu, time = %lld us",
262 index, (long long)presentationTimeUs);
263
264 ++state->mNumBuffersDecoded;
265 state->mNumBytesDecoded += size;
266
267 if (surface == NULL || !renderSurface) {
268 err = state->mCodec->releaseOutputBuffer(index);
269 } else if (useTimestamp) {
270 if (startTimeRender == -1) {
271 // begin rendering 2 vsyncs (~33ms) after first decode
272 startTimeRender =
273 systemTime(SYSTEM_TIME_MONOTONIC) + 33000000
274 - (presentationTimeUs * 1000);
275 }
276 presentationTimeUs =
277 (presentationTimeUs * 1000) + startTimeRender;
278 err = state->mCodec->renderOutputBufferAndRelease(
279 index, presentationTimeUs);
280 } else {
281 err = state->mCodec->renderOutputBufferAndRelease(index);
282 }
283
284 CHECK_EQ(err, (status_t)OK);
285
286 if (flags & MediaCodec::BUFFER_FLAG_EOS) {
287 ALOGV("reached EOS on output.");
288
289 state->mSawOutputEOS = true;
290 }
291 } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
292 ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
293 CHECK_EQ((status_t)OK,
294 state->mCodec->getOutputBuffers(&state->mOutBuffers));
295
296 ALOGV("got %zu output buffers", state->mOutBuffers.size());
297 } else if (err == INFO_FORMAT_CHANGED) {
298 sp<AMessage> format;
299 CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
300
301 ALOGV("INFO_FORMAT_CHANGED: %s", format->debugString().c_str());
302 } else {
303 CHECK_EQ(err, -EAGAIN);
304 }
305 }
306 }
307
308 int64_t elapsedTimeUs = ALooper::GetNowUs() - startTimeUs;
309
310 for (size_t i = 0; i < stateByTrack.size(); ++i) {
311 CodecState *state = &stateByTrack.editValueAt(i);
312
313 CHECK_EQ((status_t)OK, state->mCodec->release());
314
315 if (state->mIsAudio) {
316 printf("track %zu: %lld bytes received. %.2f KB/sec\n",
317 i,
318 (long long)state->mNumBytesDecoded,
319 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
320 } else {
321 printf("track %zu: %lld frames decoded, %.2f fps. %lld"
322 " bytes received. %.2f KB/sec\n",
323 i,
324 (long long)state->mNumBuffersDecoded,
325 state->mNumBuffersDecoded * 1E6 / elapsedTimeUs,
326 (long long)state->mNumBytesDecoded,
327 state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs);
328 }
329 }
330
331 return 0;
332 }
333
main(int argc,char ** argv)334 int main(int argc, char **argv) {
335 using namespace android;
336
337 const char *me = argv[0];
338
339 bool useAudio = false;
340 bool useVideo = false;
341 bool playback = false;
342 bool useSurface = false;
343 bool renderSurface = false;
344 bool useTimestamp = false;
345
346 int res;
347 while ((res = getopt(argc, argv, "havpSDRT")) >= 0) {
348 switch (res) {
349 case 'a':
350 {
351 useAudio = true;
352 break;
353 }
354 case 'v':
355 {
356 useVideo = true;
357 break;
358 }
359 case 'p':
360 {
361 playback = true;
362 break;
363 }
364 case 'T':
365 {
366 useTimestamp = true;
367 }
368 // fall through
369 case 'R':
370 {
371 renderSurface = true;
372 }
373 // fall through
374 case 'S':
375 {
376 useSurface = true;
377 break;
378 }
379 case '?':
380 case 'h':
381 default:
382 {
383 usage(me);
384 }
385 }
386 }
387
388 argc -= optind;
389 argv += optind;
390
391 if (argc != 1) {
392 usage(me);
393 }
394
395 if (!useAudio && !useVideo) {
396 useAudio = useVideo = true;
397 }
398
399 ProcessState::self()->startThreadPool();
400
401 DataSource::RegisterDefaultSniffers();
402
403 sp<ALooper> looper = new ALooper;
404 looper->start();
405
406 sp<SurfaceComposerClient> composerClient;
407 sp<SurfaceControl> control;
408 sp<Surface> surface;
409
410 if (playback || (useSurface && useVideo)) {
411 composerClient = new SurfaceComposerClient;
412 CHECK_EQ(composerClient->initCheck(), (status_t)OK);
413
414 sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
415 ISurfaceComposer::eDisplayIdMain));
416 DisplayInfo info;
417 SurfaceComposerClient::getDisplayInfo(display, &info);
418 ssize_t displayWidth = info.w;
419 ssize_t displayHeight = info.h;
420
421 ALOGV("display is %zd x %zd\n", displayWidth, displayHeight);
422
423 control = composerClient->createSurface(
424 String8("A Surface"),
425 displayWidth,
426 displayHeight,
427 PIXEL_FORMAT_RGB_565,
428 0);
429
430 CHECK(control != NULL);
431 CHECK(control->isValid());
432
433 SurfaceComposerClient::openGlobalTransaction();
434 CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
435 CHECK_EQ(control->show(), (status_t)OK);
436 SurfaceComposerClient::closeGlobalTransaction();
437
438 surface = control->getSurface();
439 CHECK(surface != NULL);
440 }
441
442 if (playback) {
443 sp<SimplePlayer> player = new SimplePlayer;
444 looper->registerHandler(player);
445
446 player->setDataSource(argv[0]);
447 player->setSurface(surface->getIGraphicBufferProducer());
448 player->start();
449 sleep(60);
450 player->stop();
451 player->reset();
452 } else {
453 decode(looper, argv[0], useAudio, useVideo, surface, renderSurface,
454 useTimestamp);
455 }
456
457 if (playback || (useSurface && useVideo)) {
458 composerClient->dispose();
459 }
460
461 looper->stop();
462
463 return 0;
464 }
465