diff options
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/am/src/com/android/commands/am/Am.java | 61 | ||||
-rw-r--r-- | cmds/app_process/app_main.cpp | 2 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.c | 45 | ||||
-rw-r--r-- | cmds/dumpstate/dumpstate.h | 3 | ||||
-rw-r--r-- | cmds/dumpstate/utils.c | 4 | ||||
-rw-r--r-- | cmds/pm/src/com/android/commands/pm/Pm.java | 5 | ||||
-rw-r--r-- | cmds/screenshot/Android.mk | 16 | ||||
-rw-r--r-- | cmds/screenshot/screenshot.c | 171 | ||||
-rw-r--r-- | cmds/stagefright/Android.mk | 25 | ||||
-rw-r--r-- | cmds/stagefright/recordvideo.cpp | 303 |
10 files changed, 624 insertions, 11 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index f2aa91f..b073004 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -102,6 +102,8 @@ public class Am { sendBroadcast(); } else if (op.equals("profile")) { runProfile(); + } else if (op.equals("dumpheap")) { + runDumpHeap(); } else if (op.equals("monitor")) { runMonitor(); } else { @@ -146,6 +148,31 @@ public class Am { String value = nextArgRequired(); intent.putExtra(key, Integer.valueOf(value)); hasIntentInfo = true; + } else if (opt.equals("--eia")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + String[] strings = value.split(","); + int[] list = new int[strings.length]; + for (int i = 0; i < strings.length; i++) { + list[i] = Integer.valueOf(strings[i]); + } + intent.putExtra(key, list); + hasIntentInfo = true; + } else if (opt.equals("--el")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + intent.putExtra(key, Long.valueOf(value)); + hasIntentInfo = true; + } else if (opt.equals("--ela")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + String[] strings = value.split(","); + long[] list = new long[strings.length]; + for (int i = 0; i < strings.length; i++) { + list[i] = Long.valueOf(strings[i]); + } + intent.putExtra(key, list); + hasIntentInfo = true; } else if (opt.equals("--ez")) { String key = nextArgRequired(); String value = nextArgRequired(); @@ -430,6 +457,28 @@ public class Am { } } + private void runDumpHeap() throws Exception { + boolean managed = !"-n".equals(nextOption()); + String process = nextArgRequired(); + String heapFile = nextArgRequired(); + ParcelFileDescriptor fd = null; + + try { + fd = ParcelFileDescriptor.open( + new File(heapFile), + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_READ_WRITE); + } catch (FileNotFoundException e) { + System.err.println("Error: Unable to open file: " + heapFile); + return; + } + + if (!mAm.dumpHeap(process, managed, heapFile, fd)) { + throw new AndroidException("HEAP DUMP FAILED on process " + process); + } + } + class MyActivityController extends IActivityController.Stub { final String mGdbPort; @@ -894,8 +943,15 @@ public class Am { " -p <FILE>: write profiling data to <FILE>\n" + " -w: wait for instrumentation to finish before returning\n" + "\n" + + " run a test package against an application: am instrument [flags] <TEST_PACKAGE>/<RUNNER_CLASS>\n" + + " -e <testrunner_flag> <testrunner_value> [,<testrunner_value>]\n" + + " -w wait for the test to finish (required)\n" + + " -r use with -e perf true to generate raw output for performance measurements\n" + + "\n" + " start profiling: am profile <PROCESS> start <FILE>\n" + " stop profiling: am profile <PROCESS> stop\n" + + " dump heap: am dumpheap [flags] <PROCESS> <FILE>\n" + + " -n: dump native heap instead of managed heap\n" + "\n" + " start monitoring: am monitor [--gdb <port>]\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + @@ -906,7 +962,10 @@ public class Am { " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + " [--esn <EXTRA_KEY> ...]\n" + " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + - " [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + + " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + + " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + + " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + + " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + " [-n <COMPONENT>] [-f <FLAGS>]\n" + " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + " [--debug-log-resolution]\n" + diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 7decf9a..0159edd 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -171,9 +171,9 @@ int main(int argc, const char* const argv[]) runtime.start(); } } else { - LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); fprintf(stderr, "Error: no class name or --zygote supplied.\n"); app_usage(); + LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); return 10; } diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index 822f62d..67bd9f7 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -39,6 +39,8 @@ static char cmdline_buf[16384] = "(unknown)"; static const char *dump_traces_path = NULL; +static char screenshot_path[PATH_MAX] = ""; + /* dumps the current system state to stdout */ static void dumpstate() { time_t now = time(NULL); @@ -76,6 +78,12 @@ static void dumpstate() { dump_file("SLAB INFO", "/proc/slabinfo"); dump_file("ZONEINFO", "/proc/zoneinfo"); + if (screenshot_path[0]) { + LOGI("taking screenshot\n"); + run_command(NULL, 5, "su", "root", "screenshot", screenshot_path, NULL); + LOGI("wrote screenshot: %s\n", screenshot_path); + } + run_command("SYSTEM LOG", 20, "logcat", "-v", "time", "-d", "*:v", NULL); /* show the traces we collected in main(), if that was done */ @@ -103,7 +111,12 @@ static void dumpstate() { dump_file("NETWORK ROUTES", "/proc/net/route"); dump_file("ARP CACHE", "/proc/net/arp"); + run_command("WIFI NETWORKS", 20, + "su", "root", "wpa_cli", "list_networks", NULL); + #ifdef FWDUMP_bcm4329 + run_command("DUMP WIFI STATUS", 20, + "su", "root", "dhdutil", "-i", "eth0", "dump", NULL); run_command("DUMP WIFI FIRMWARE LOG", 60, "su", "root", "dhdutil", "-i", "eth0", "upload", "/data/local/tmp/wlan_crash.dump", NULL); #endif @@ -164,18 +177,25 @@ static void dumpstate() { } static void usage() { - fprintf(stderr, "usage: dumpstate [-d] [-o file] [-s] [-z]\n" - " -d: append date to filename (requires -o)\n" + fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s]\n" " -o: write to file (instead of stdout)\n" + " -d: append date to filename (requires -o)\n" + " -z: gzip output (requires -o)\n" + " -p: capture screenshot to filename.png (requires -o)\n" " -s: write output to control socket (for init)\n" - " -z: gzip output (requires -o)\n"); + " -b: play sound file instead of vibrate, at beginning of job\n" + " -e: play sound file instead of vibrate, at end of job\n" + ); } int main(int argc, char *argv[]) { int do_add_date = 0; int do_compress = 0; char* use_outfile = 0; + char* begin_sound = 0; + char* end_sound = 0; int use_socket = 0; + int do_fb = 0; LOGI("begin\n"); @@ -191,13 +211,16 @@ int main(int argc, char *argv[]) { dump_traces_path = dump_vm_traces(); int c; - while ((c = getopt(argc, argv, "dho:svz")) != -1) { + while ((c = getopt(argc, argv, "b:de:ho:svzp")) != -1) { switch (c) { + case 'b': begin_sound = optarg; break; case 'd': do_add_date = 1; break; + case 'e': end_sound = optarg; break; case 'o': use_outfile = optarg; break; case 's': use_socket = 1; break; case 'v': break; // compatibility no-op case 'z': do_compress = 6; break; + case 'p': do_fb = 1; break; case '?': printf("\n"); case 'h': usage(); @@ -244,6 +267,10 @@ int main(int argc, char *argv[]) { strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now)); strlcat(path, date, sizeof(path)); } + if (do_fb) { + strlcpy(screenshot_path, path, sizeof(screenshot_path)); + strlcat(screenshot_path, ".png", sizeof(screenshot_path)); + } strlcat(path, ".txt", sizeof(path)); if (do_compress) strlcat(path, ".gz", sizeof(path)); strlcpy(tmp_path, path, sizeof(tmp_path)); @@ -251,16 +278,18 @@ int main(int argc, char *argv[]) { gzip_pid = redirect_to_file(stdout, tmp_path, do_compress); } - /* bzzzzzz */ - if (vibrator) { + if (begin_sound) { + play_sound(begin_sound); + } else if (vibrator) { fputs("150", vibrator); fflush(vibrator); } dumpstate(); - /* bzzz bzzz bzzz */ - if (vibrator) { + if (end_sound) { + play_sound(end_sound); + } else if (vibrator) { int i; for (i = 0; i < 3; i++) { fputs("75\n", vibrator); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 682eafd..83b1d11 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -44,4 +44,7 @@ void for_each_pid(void (*func)(int, const char *), const char *header); /* Displays a blocked processes in-kernel wait channel */ void show_wchan(int pid, const char *name); +/* Play a sound via Stagefright */ +void play_sound(const char* path); + #endif /* _DUMPSTATE_H_ */ diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index c7a78cc..f92acbb 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -429,3 +429,7 @@ const char *dump_vm_traces() { rename(anr_traces_path, traces_path); return dump_traces_path; } + +void play_sound(const char* path) { + run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL); +} diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 9b8b0ac..040421a 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -233,7 +233,7 @@ public final class Pm { for (int i=0; i<rawList.length; i++) { list.add(rawList[i]); } - + // Sort by name Collections.sort(list, new Comparator<FeatureInfo>() { @@ -909,6 +909,9 @@ public final class Pm { System.err.println("The list instrumentation command prints all instrumentations,"); System.err.println("or only those that target a specified package. Options:"); System.err.println(" -f: see their associated file."); + System.err.println("(Use this command to list all test packages, or use <TARGET-PACKAGE> "); + System.err.println(" to list the test packages for a particular application. The -f "); + System.err.println(" option lists the .apk file for the test package.)"); System.err.println(""); System.err.println("The list features command prints all features of the system."); System.err.println(""); diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk new file mode 100644 index 0000000..99c7aeb --- /dev/null +++ b/cmds/screenshot/Android.mk @@ -0,0 +1,16 @@ +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := screenshot.c + +LOCAL_MODULE := screenshot + +LOCAL_SHARED_LIBRARIES := libcutils libz +LOCAL_STATIC_LIBRARIES := libpng +LOCAL_C_INCLUDES += external/zlib + +include $(BUILD_EXECUTABLE) + +endif diff --git a/cmds/screenshot/screenshot.c b/cmds/screenshot/screenshot.c new file mode 100644 index 0000000..048636c --- /dev/null +++ b/cmds/screenshot/screenshot.c @@ -0,0 +1,171 @@ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> + +#include <linux/fb.h> + +#include <zlib.h> +#include <libpng/png.h> + +#include "private/android_filesystem_config.h" + +#define LOG_TAG "screenshot" +#include <utils/Log.h> + +void take_screenshot(FILE *fb_in, FILE *fb_out) { + int fb; + char imgbuf[0x10000]; + struct fb_var_screeninfo vinfo; + png_structp png; + png_infop info; + unsigned int r,c,rowlen; + unsigned int bytespp,offset; + + fb = fileno(fb_in); + if(fb < 0) { + LOGE("failed to open framebuffer\n"); + return; + } + fb_in = fdopen(fb, "r"); + + if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) { + LOGE("failed to get framebuffer info\n"); + return; + } + fcntl(fb, F_SETFD, FD_CLOEXEC); + + png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png == NULL) { + LOGE("failed png_create_write_struct\n"); + fclose(fb_in); + return; + } + + png_init_io(png, fb_out); + info = png_create_info_struct(png); + if (info == NULL) { + LOGE("failed png_create_info_struct\n"); + png_destroy_write_struct(&png, NULL); + fclose(fb_in); + return; + } + if (setjmp(png_jmpbuf(png))) { + LOGE("failed png setjmp\n"); + png_destroy_write_struct(&png, NULL); + fclose(fb_in); + return; + } + + bytespp = vinfo.bits_per_pixel / 8; + png_set_IHDR(png, info, + vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, + PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png, info); + + rowlen=vinfo.xres * bytespp; + if (rowlen > sizeof(imgbuf)) { + LOGE("crazy rowlen: %d\n", rowlen); + png_destroy_write_struct(&png, NULL); + fclose(fb_in); + return; + } + + offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp; + fseek(fb_in, offset, SEEK_SET); + + for(r=0; r<vinfo.yres; r++) { + int len = fread(imgbuf, 1, rowlen, fb_in); + if (len <= 0) break; + png_write_row(png, (png_bytep)imgbuf); + } + + png_write_end(png, info); + fclose(fb_in); + png_destroy_write_struct(&png, NULL); +} + +void fork_sound(const char* path) { + pid_t pid = fork(); + if (pid == 0) { + execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL); + } +} + +void usage() { + fprintf(stderr, + "usage: screenshot [-s soundfile] filename.png\n" + " -s: play a sound effect to signal success\n" + " -i: autoincrement to avoid overwriting filename.png\n" + ); +} + +int main(int argc, char**argv) { + FILE *png = NULL; + FILE *fb_in = NULL; + char outfile[PATH_MAX] = ""; + + char * soundfile = NULL; + int do_increment = 0; + + int c; + while ((c = getopt(argc, argv, "s:i")) != -1) { + switch (c) { + case 's': soundfile = optarg; break; + case 'i': do_increment = 1; break; + case '?': + case 'h': + usage(); exit(1); + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(); exit(1); + } + + strlcpy(outfile, argv[0], PATH_MAX); + if (do_increment) { + struct stat st; + char base[PATH_MAX] = ""; + int i = 0; + while (stat(outfile, &st) == 0) { + if (!base[0]) { + char *p = strrchr(outfile, '.'); + if (p) *p = '\0'; + strcpy(base, outfile); + } + snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i); + } + } + + fb_in = fopen("/dev/graphics/fb0", "r"); + if (!fb_in) { + fprintf(stderr, "error: could not read framebuffer\n"); + exit(1); + } + + /* switch to non-root user and group */ + gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; + setgroups(sizeof(groups)/sizeof(groups[0]), groups); + setuid(AID_SHELL); + + png = fopen(outfile, "w"); + if (!png) { + fprintf(stderr, "error: writing file %s: %s\n", + outfile, strerror(errno)); + exit(1); + } + + take_screenshot(fb_in, png); + + if (soundfile) { + fork_sound(soundfile); + } + + exit(0); +} diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk index 9a97284..cbdf119 100644 --- a/cmds/stagefright/Android.mk +++ b/cmds/stagefright/Android.mk @@ -53,6 +53,31 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ SineSource.cpp \ + recordvideo.cpp + +LOCAL_SHARED_LIBRARIES := \ + libstagefright liblog libutils libbinder + +LOCAL_C_INCLUDES:= \ + $(JNI_H_INCLUDE) \ + frameworks/base/media/libstagefright \ + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include + +LOCAL_CFLAGS += -Wno-multichar + +LOCAL_MODULE_TAGS := debug + +LOCAL_MODULE:= recordvideo + +include $(BUILD_EXECUTABLE) + + +################################################################################ + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + SineSource.cpp \ audioloop.cpp LOCAL_SHARED_LIBRARIES := \ diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp new file mode 100644 index 0000000..f8eb514 --- /dev/null +++ b/cmds/stagefright/recordvideo.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SineSource.h" + +#include <binder/ProcessState.h> +#include <media/stagefright/AudioPlayer.h> +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/MPEG4Writer.h> +#include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> +#include <media/MediaPlayerInterface.h> + +using namespace android; + +// Print usage showing how to use this utility to record videos +static void usage(const char *me) { + fprintf(stderr, "usage: %s\n", me); + fprintf(stderr, " -h(elp)\n"); + fprintf(stderr, " -b bit rate in bits per second (default: 300000)\n"); + fprintf(stderr, " -c YUV420 color format: [0] semi planar or [1] planar (default: 1)\n"); + fprintf(stderr, " -f frame rate in frames per second (default: 30)\n"); + fprintf(stderr, " -i I frame interval in seconds (default: 1)\n"); + fprintf(stderr, " -n number of frames to be recorded (default: 300)\n"); + fprintf(stderr, " -w width in pixels (default: 176)\n"); + fprintf(stderr, " -t height in pixels (default: 144)\n"); + fprintf(stderr, " -l encoder level. see omx il header (default: encoder specific)\n"); + fprintf(stderr, " -p encoder profile. see omx il header (default: encoder specific)\n"); + fprintf(stderr, " -v video codec: [0] AVC [1] M4V [2] H263 (default: 0)\n"); + fprintf(stderr, "The output file is /sdcard/output.mp4\n"); + exit(1); +} + +class DummySource : public MediaSource { + +public: + DummySource(int width, int height, int nFrames, int fps, int colorFormat) + : mWidth(width), + mHeight(height), + mMaxNumFrames(nFrames), + mFrameRate(fps), + mColorFormat(colorFormat), + mSize((width * height * 3) / 2) { + + mGroup.add_buffer(new MediaBuffer(mSize)); + + // Check the color format to make sure + // that the buffer size mSize it set correctly above. + CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar || + colorFormat == OMX_COLOR_FormatYUV420Planar); + } + + virtual sp<MetaData> getFormat() { + sp<MetaData> meta = new MetaData; + meta->setInt32(kKeyWidth, mWidth); + meta->setInt32(kKeyHeight, mHeight); + meta->setInt32(kKeyColorFormat, mColorFormat); + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); + + return meta; + } + + virtual status_t start(MetaData *params) { + mNumFramesOutput = 0; + return OK; + } + + virtual status_t stop() { + return OK; + } + + virtual status_t read( + MediaBuffer **buffer, const MediaSource::ReadOptions *options) { + + if (mNumFramesOutput % 10 == 0) { + fprintf(stderr, "."); + } + if (mNumFramesOutput == mMaxNumFrames) { + return ERROR_END_OF_STREAM; + } + + status_t err = mGroup.acquire_buffer(buffer); + if (err != OK) { + return err; + } + + // We don't care about the contents. we just test video encoder + // Also, by skipping the content generation, we can return from + // read() much faster. + //char x = (char)((double)rand() / RAND_MAX * 255); + //memset((*buffer)->data(), x, mSize); + (*buffer)->set_range(0, mSize); + (*buffer)->meta_data()->clear(); + (*buffer)->meta_data()->setInt64( + kKeyTime, (mNumFramesOutput * 1000000) / mFrameRate); + ++mNumFramesOutput; + + return OK; + } + +protected: + virtual ~DummySource() {} + +private: + MediaBufferGroup mGroup; + int mWidth, mHeight; + int mMaxNumFrames; + int mFrameRate; + int mColorFormat; + size_t mSize; + int64_t mNumFramesOutput;; + + DummySource(const DummySource &); + DummySource &operator=(const DummySource &); +}; + +enum { + kYUV420SP = 0, + kYUV420P = 1, +}; + +// returns -1 if mapping of the given color is unsuccessful +// returns an omx color enum value otherwise +static int translateColorToOmxEnumValue(int color) { + switch (color) { + case kYUV420SP: + return OMX_COLOR_FormatYUV420SemiPlanar; + case kYUV420P: + return OMX_COLOR_FormatYUV420Planar; + default: + fprintf(stderr, "Unsupported color: %d\n", color); + return -1; + } +} + +int main(int argc, char **argv) { + + // Default values for the program if not overwritten + int frameRateFps = 30; + int width = 176; + int height = 144; + int bitRateBps = 300000; + int iFramesIntervalSeconds = 1; + int colorFormat = OMX_COLOR_FormatYUV420Planar; + int nFrames = 300; + int level = -1; // Encoder specific default + int profile = -1; // Encoder specific default + int codec = 0; + const char *fileName = "/sdcard/output.mp4"; + + android::ProcessState::self()->startThreadPool(); + int res; + while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:h")) >= 0) { + switch (res) { + case 'b': + { + bitRateBps = atoi(optarg); + break; + } + + case 'c': + { + colorFormat = translateColorToOmxEnumValue(atoi(optarg)); + if (colorFormat == -1) { + usage(argv[0]); + } + break; + } + + case 'f': + { + frameRateFps = atoi(optarg); + break; + } + + case 'i': + { + iFramesIntervalSeconds = atoi(optarg); + break; + } + + case 'n': + { + nFrames = atoi(optarg); + break; + } + + case 'w': + { + width = atoi(optarg); + break; + } + + case 't': + { + height = atoi(optarg); + break; + } + + case 'l': + { + level = atoi(optarg); + break; + } + + case 'p': + { + profile = atoi(optarg); + break; + } + + case 'v': + { + codec = atoi(optarg); + if (codec < 0 || codec > 2) { + usage(argv[0]); + } + break; + } + + case 'h': + default: + { + usage(argv[0]); + break; + } + } + } + + OMXClient client; + CHECK_EQ(client.connect(), OK); + + status_t err = OK; + sp<MediaSource> source = + new DummySource(width, height, nFrames, frameRateFps, colorFormat); + + sp<MetaData> enc_meta = new MetaData; + switch (codec) { + case 1: + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + break; + case 2: + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); + break; + default: + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); + break; + } + enc_meta->setInt32(kKeyWidth, width); + enc_meta->setInt32(kKeyHeight, height); + enc_meta->setInt32(kKeySampleRate, frameRateFps); + enc_meta->setInt32(kKeyBitRate, bitRateBps); + enc_meta->setInt32(kKeyStride, width); + enc_meta->setInt32(kKeySliceHeight, height); + enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds); + enc_meta->setInt32(kKeyColorFormat, colorFormat); + if (level != -1) { + enc_meta->setInt32(kKeyVideoLevel, level); + } + if (profile != -1) { + enc_meta->setInt32(kKeyVideoProfile, profile); + } + + sp<MediaSource> encoder = + OMXCodec::Create( + client.interface(), enc_meta, true /* createEncoder */, source); + + sp<MPEG4Writer> writer = new MPEG4Writer(fileName); + writer->addSource(encoder); + int64_t start = systemTime(); + CHECK_EQ(OK, writer->start()); + while (!writer->reachedEOS()) { + } + err = writer->stop(); + int64_t end = systemTime(); + + fprintf(stderr, "$\n"); + client.disconnect(); + + if (err != OK && err != ERROR_END_OF_STREAM) { + fprintf(stderr, "record failed: %d\n", err); + return 1; + } + fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000); + fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start)); + return 0; +} |