将本地的StageFright特性包含在我的Android项目中

14

我目前正在开发一个需要录制音频、将其编码为AAC、进行流传输并进行反向操作-接收流、解码AAC并播放音频的应用程序。

我成功使用MediaRecorder记录了包装在MP4容器中的AAC,使用AudioRecord类成功上载音频。但是,我需要能够在流传输时对音频进行编码,但这些类似乎都没有帮助我做到这一点。

我进行了一些研究,并发现大多数遇到此问题的人最终都会使用像ffmpeg这样的本地库。

但是我想知道,既然Android已经包括了StageFright,它具有可以进行编码和解码的本地代码(例如,AAC编码AAC解码),是否有办法在我的应用程序中使用该本地代码?我该怎么做呢?

如果我只需要实现一些JNI类及其本地代码,那将非常好。另外,由于它是一个Android库,因此不会有任何许可问题(如果我错了,请纠正我)。

1个回答

17

是的,你可以使用libstagefright,它非常强大。

由于stagefright未暴露给NDK,所以您需要做额外的工作。

有两种方法:

(1) 使用Android完整源代码构建您的项目。这种方式需要花费几天时间进行设置,一旦设置好了,就非常容易,并且您可以充分利用stagefright。

(2) 您可以将include文件夹复制到您的项目中,它位于此文件夹中:

android-4.0.4_r1.1/frameworks/base/include/media/stagefright

然后,您需要通过动态加载libstagefright.so来导出库函数,并将其与JNI项目链接。

使用statgefright进行编码/解码非常简单,只需要几百行即可完成。

我使用stagefright捕获屏幕截图创建视频,该视频将很快在我们的Android VNC服务器上发布。

以下是一段代码片段,我认为它比使用ffmpeg编码电影更好。您也可以添加音频源。

class ImageSource : public MediaSource {
   ImageSource(int width, int height, int colorFormat)
    : mWidth(width),
      mHeight(height),
      mColorFormat(colorFormat)
   {
   }

   virtual status_t read(
        MediaBuffer **buffer, const MediaSource::ReadOptions *options) {
       // here you can fill the buffer with your pixels
   }

   ...
};

int width = 720;
int height = 480;
sp<MediaSource> img_source = new ImageSource(width, height, colorFormat);

sp<MetaData> enc_meta = new MetaData;
// enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
// enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
enc_meta->setInt32(kKeyWidth, width);
enc_meta->setInt32(kKeyHeight, height);
enc_meta->setInt32(kKeySampleRate, kFramerate);
enc_meta->setInt32(kKeyBitRate, kVideoBitRate);
enc_meta->setInt32(kKeyStride, width);
enc_meta->setInt32(kKeySliceHeight, height);
enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec);
enc_meta->setInt32(kKeyColorFormat, colorFormat);

sp<MediaSource> encoder =
    OMXCodec::Create(
            client.interface(), enc_meta, true, image_source);

sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/screenshot.mp4");
writer->addSource(encoder);

// you can add an audio source here if you want to encode audio as well
// 
//sp<MediaSource> audioEncoder =
//    OMXCodec::Create(client.interface(), encMetaAudio, true, audioSource);
//writer->addSource(audioEncoder);

writer->setMaxFileDuration(kDurationUs);
CHECK_EQ(OK, writer->start());
while (!writer->reachedEOS()) {
    fprintf(stderr, ".");
    usleep(100000);
}
err = writer->stop();

2
在复制时,请注意JNI函数是C语言,而Stagefright是C ++。 Stagefright引入的一些依赖头文件似乎与JNI的NDK环境不兼容。 - Marcus Wolschon
2
请注意,并非所有的Android设备都具有stagefright功能,而且API也因版本而异。由于这些API没有合同,可能不稳定,请非常小心。 - dagalpin
我无法给这个点赞足够的次数,谢谢你,在libstagefright上好的信息太少了。 - Baggers
你需要从整个 Android 源代码树中进行此操作。请按照这里的说明进行操作:http://source.android.com/source/initializing.html,一旦您能够构建整个源代码树,就可以使用 stagefright。 - huisinro
由于Stagefright高度依赖于版本,因此您需要为每个不同的Android版本构建不同的.so文件。在您的Java代码中,您可以根据Android API级别加载这些.so文件。 - huisinro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接