利用 android mediaRecorder c++类进行视频编码

本例中media source为camera。(学习的平台是android sdk6.0)

调用关系图:


startRecording:

1.     recorder = New MediaRecorder(String16());

classMediaRecorder : public BnMediaRecorderClient,

                      public virtualIMediaDeathNotifier

a)      在创建mediaRecorder的时侯,我们先获取IMediaPlayerService指针,然后再创建IMediaRecorder

(关于的声明sp<IMediaRecorder>          mMediaRecorder;)

        mMediaRecorder =service->createMediaRecorder(opPackageName);

 

b)      在service->createMediaRecorder中会先把对象IMediaPlayerService序列话(利用data打包),然后把请求CREATE_MEDIA_RECORDER发送给remote(就是bpbinder)处理

remote()->transact(CREATE_MEDIA_RECORDER, data,&reply);

c)       最后根据远端的reply来创建本地对应的对象

interface_cast<IMediaRecorder>(reply.readStrongBinder());

2.     后续的方法都通过BpMediaRecorder(remote)来发送到BnMediaRecorder操作。

a)      BnMediaRecorder继承了BnInterface<IMediaRecorder>,并实现了ontransact

classBnMediaRecorder: publicBnInterface<IMediaRecorder>

{

public:

    virtual status_t    onTransact( uint32_t code,

                                    constParcel& data,

                                    Parcel*reply,

                                    uint32_tflags = 0);

};

b)      在这个方法里,每个操作都有对应的处理分支

c)       BnMediaRecorder是个虚函数,具体工作由MediaRecorderClient来完成:MediaRecorderClient : public BnMediaRecorder

d)      class BpMediaRecorder: public BpInterface<IMediaRecorder>

在对应的方法中最后都通过remote送给Bn处理,如:

Parceldata, reply;

data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());

data.writeString8(params);

    remote()->transact(SET_PARAMETERS,data, &reply);

e)      recorder->setParameters(…….)

f)       recorder->prepare()

g)      recorder->start()

3.     在MediaRecorderClient中封装了MediaRecorderBase这个类,每一项任务都要它来完成

在MediaRecorderClient的构造函数中可以看到

   mRecorder = AVMediaServiceFactory::get()->createStagefrightRecorder(opPackageName);

a)      因此,具体的工作由StagefrightRecorder来完成

b)      在AVMediaServiceFactory.cpp中

StagefrightRecorder*AVMediaServiceFactory::createStagefrightRecorder(

        const String16 &opPackageName) {

    return newStagefrightRecorder(opPackageName);

}

4.     StagefrightRecorder  recorder->start()

在prepare中或者start中调用StagefrightRecorder::prepareInternal()

在这里根据输出编码设定,选择对应的编码器进行初始化。

我们以OUTPUT_FORMAT_MPEG_4为例进行分析

根据输出格式进入setupMPEG4orWEBMRecording()

5.     setupMPEG4orWEBMRecording()

在这里创建了MPEG4Writer

a)      writer = mp4writer =AVFactory::get()->CreateMPEG4Writer(mOutputFd);

b)      setupMediaSource将camera指定为encoder的input source

c)       sp<MediaSource> encoder;

err = setupVideoEncoder(mediaSource, &encoder);创建encoder

d)      setupVideoEncoder(mediaSource,&encoder);

首先将camera中的各项参数设定读出来设入到encoder中(camera为null则使用default值)

sp<MetaData>meta = cameraSource->getFormat();

 

        int32_t width, height, stride,sliceHeight, colorFormat;

        CHECK(meta->findInt32(kKeyWidth,&width));

        CHECK(meta->findInt32(kKeyHeight,&height));

        CHECK(meta->findInt32(kKeyStride,&stride));

       CHECK(meta->findInt32(kKeySliceHeight, &sliceHeight));

       CHECK(meta->findInt32(kKeyColorFormat, &colorFormat));

 

        format->setInt32("width",width);

        format->setInt32("height",height);

        format->setInt32("stride",stride);

       format->setInt32("slice-height", sliceHeight);

       format->setInt32("color-format", colorFormat);

这里预留了custom参数设置函数,android中默认没有实现,是空函数

接着创建encoder。

    sp<MediaCodecSource> encoder =MediaCodecSource::Create(

            mLooper, format, cameraSource,mPersistentSurface, flags);

e)          sp<MediaCodecSource> encoder

=MediaCodecSource::Create(             

mLooper,

 format,

cameraSource,

 mPersistentSurface,

flags);

在create函数中先new一个对象,

   sp<MediaCodecSource> mediaSource =

           new MediaCodecSource(looper, format, source, consumer, flags);

 

   if (mediaSource->init() == OK) {

       return mediaSource;

    }

f)       MediaCodecSource::init()

status_t err = initEncoder();

g)      initEncoder(){

mReflector = new AHandlerReflector<MediaCodecSource>(this);

mLooper->registerHandler(mReflector);

 

    mCodecLooper = new ALooper;

   mCodecLooper->setName("codec_looper");

mCodecLooper->start();

……………..

        mEncoder =MediaCodec::CreateByType(

            mCodecLooper,outputMIME.c_str(), true /* encoder */);

….

    mEncoderActivityNotify =new AMessage(kWhatEncoderActivity, mReflector);

   mEncoder->setCallback(mEncoderActivityNotify);

 

    status_t err =mEncoder->configure(

                mOutputFormat,

                NULL /*nativeWindow */,

                NULL /* crypto*/,

               MediaCodec::CONFIGURE_FLAG_ENCODE);

…………………………

 

    err = mEncoder->start();

h)        MediaCodec::CreateByType(

mCodecLooper, outputMIME.c_str(), true /* encoder */) {

            sp<MediaCodec> codec = new MediaCodec(looper, pid);

 

    const status_tret = codec->init(mime, true /* nameIsType */, encoder);

}

 

i)        MediaCodec::init (const AString&name, bool nameIsType, bool encoder) {

………..

/// name 包含video, nameIsType is true

因此

        mCodec =AVFactory::get()->createACodec();

…………..

        mIsVideo =true;

…………..

       mCodecLooper->registerHandler(mCodec);

    mCodec->setNotificationMessage(newAMessage(kWhatCodecNotify, this));

 

    sp<AMessage> msg = newAMessage(kWhatInit, this);

    msg->setString("name", name);

    msg->setInt32("nameIsType",nameIsType);

 

    if (nameIsType) {

        msg->setInt32("encoder",encoder);

    }

 

    status_t err;

Vector<MediaResource> resources;

    const char *type = secureCodec ?kResourceSecureCodec : kResourceNonSecureCodec;

    const char *subtype = mIsVideo ?kResourceVideoCodec : kResourceAudioCodec;

   resources.push_back(MediaResource(String8(type), String8(subtype), 1));

    for (int i = 0; i <= kMaxRetry; ++i) {

        if (i > 0) {

            // Don't try to reclaim resourcefor the first time.

            if(!mResourceManagerService->reclaimResource(resources)) {

                break;

            }

        }

 

        sp<AMessage> response;

        err = PostAndAwaitResponse(msg,&response);

        if (!isResourceError(err)) {

            break;

        }

    }

}

发布了1 篇原创文章 · 获赞 1 · 访问量 750
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览