Confirmed users
157
edits
No edit summary |
No edit summary |
||
Line 13: | Line 13: | ||
</p> | </p> | ||
[[File:MediaRecorder Arch.jpg|400px ]] | [[File:MediaRecorder Arch.jpg|400px ]] | ||
<p>API Draft(incomplete 2013/01/29) </p> | |||
<code> | |||
class MediaSegmentAdapter { | |||
public: | |||
/* AppendSegment may run on MediaStreamGraph thread to avoid race condition */ | |||
void AppendSegment(MediaSegment) = 0; | |||
void SetBufferLength(size_t); | |||
size_t GetBufferLength(); | |||
MediaSegment DequeueSegment(); | |||
protected: | |||
Queue<MediaSegment> mBuffer; | |||
} | |||
class VideoAdapter : MediaSegmentAdapter { | |||
public: | |||
/* This version deep copy/color convert the input buffer into a local buffer */ | |||
void AppendSegment(MediaSegment); | |||
} | |||
class GrallocAdapter : MediaSegmentAdapter { | |||
public: | |||
/* This version |do not| copy frame data, but queue the GraphicBuffer directly | |||
which can be used with SurfaceMediaSource or other SurfaceFlinger compatible | |||
mechanism for hardware supported video encoding */ | |||
void AppendSegment(MediaSegment); | |||
} | |||
class AudioAdapter : MediaSegmentAdapter { | |||
public: | |||
/* Copy/resample the data into local buffer */ | |||
void AppendSegment(MediaSegment); | |||
} | |||
class MediaEncoder : MediaStreamListener { | |||
public: | |||
/* Callback functions for MediaStream */ | |||
void NotifyConsumption(MediaStreamGraph, Consumption); | |||
void NotifyPull(MediaStreamGraph, StreamTime); | |||
void NotifyBlockingChanged(MediaStreamGraph, Blocking); | |||
void NotifyHasCurrentData(MediaStreamGraph, bool); | |||
void NotifyOutput(MediaStreamGraph); | |||
void NotifyFinished(MediaStreamGraph); | |||
/* Queue the MediaSegment into correspond adapters */ | |||
/* XXX: Is it possible to determine Audio related paramenters from this callback? | |||
Or we have to query them from MediaStream directly? */ | |||
/* AppendSegment into Adapter need block MediaStreamGraph thread to avoid race condition | |||
and we should schedule one encoding loop if any track updated */ | |||
void NotifyQueuedTrackChanges(MediaStreamGraph, TrackID, TrackRate, TrackTicks, uint32_t, MediaSegment); | |||
/* Callback functions to JS */ | |||
void SetDataAvailableCallback() | |||
void SetErrorCallback() | |||
void SetMuteTrackCallback() | |||
void SetPauseCallback() | |||
void SetPhotoCallback() | |||
void SetRecordingCallback() | |||
void SetResumeCallback() | |||
void SetStopCallback() | |||
void SetUnmuteTrackCallback() | |||
void SetWarningCallback() | |||
/* Option query functions */ | |||
Vector<String> GetSupportMIMEType() | |||
Pair<int, int> GetSupportWidth() | |||
Pair<int, int> GetSupportHeight() | |||
/* Set requested encoder */ | |||
void SetMIMEType(); | |||
void SetVideoWidth(); | |||
void SetVideoHeight(); | |||
/* JS control functions */ | |||
void MuteTrack(TrackID) | |||
void Pause() | |||
void Record() | |||
void RequestData --? | |||
- Cause encoder flush data & callback? | |||
void Resume() | |||
void SetOptions() | |||
void Stop() | |||
void TakePhoto --? | |||
void UnmuteTrack | |||
/* initial internal state and codecs */ | |||
void Init() | |||
/* create MediaEncoder for given MediaStream */ | |||
MediaEncoder(MediaStream); | |||
private: | |||
void QueueVideoSegments(); | |||
void QueueAudioSegments(); | |||
void SelectCodec(); | |||
void ConfigCodec(); | |||
void SetVideoQueueSize(); | |||
void SetAudioQueueSize(); | |||
/* data member */ | |||
MediaSegmentAdapter mVideoSegments; | |||
MediaSegmentAdapter mAudioSegments; | |||
MediaCodec mVideoCodec; | |||
MediaCodec mAudioCodec; | |||
MediaWriter mWriter; | |||
Thread mEncoderThread; | |||
} | |||
/* base class for general codecs */ | |||
class MediaCodec { | |||
public: | |||
enum EncoderStatus { | |||
ENCODE, | |||
COLLECT, | |||
} | |||
void Init() = 0; | |||
/* Mimic android::CameraParameter to collect backend codec related params in general class */ | |||
void GetParams() = 0; | |||
void SetParams() = 0; | |||
/* blocking call, may buffering data and real encode until enough data collected */ | |||
EncoderStatus Encode(MediaBuffer in, void* out, size_t length) = 0; | |||
void Flush() = 0; | |||
} | |||
class AudioCodec : public MediaCodec { | |||
public: | |||
/* AudioCodec may need collect enough buffers to be encode, return COLLECT as needed */ | |||
EncoderStatus Encode(MediaBuffer in, void* out, size_t length) = 0; | |||
private: | |||
bool IsDataEnough(); | |||
void* mLocalBuffer[MIN_FRAMES]; | |||
} | |||
class VideoCodec : public MediaCodec { | |||
public: | |||
EncoderStatus Encode(MediaBuffer in, void* out, size_t length) = 0; | |||
} | |||
class OpusCodec : public AudioCodec { | |||
// Use libopus to encode audio | |||
private: | |||
// libopus ctx, etc... | |||
} | |||
class TheoraCodec : public VideoCodec { | |||
// Use libtheora to encode video | |||
private: | |||
// libtheora encoder is not blocking, thus we have to loop until frame complete | |||
} | |||
// XXX: | |||
class MediaWriter; | |||
</code> |