I would like to use iphone camera & microphone to capture information pushed out through FFMPEG RTMP Streaming
The following Function capture information on IOS
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
if (connection == videoCaptureConnection)
{
[manager264 encoderToH264:sampleBuffer];
}
else if (connection == audioCaptureConnection)
{
[manager264 encoderToMP3:sampleBuffer];
}
}
Initialization FFMPEG
- (int)setX264Resource
{
Global_Variables_VVV = (AppDelegate *)[[UIApplication sharedApplication] delegate];
avformat_network_init();
av_register_all();
pFormatCtx = avformat_alloc_context();
avformat_alloc_output_context2(&pFormatCtx, NULL, "flv", out_file);
fmt = pFormatCtx->oformat;
//Open output URL
if (avio_open(&pFormatCtx->pb, out_file, AVIO_FLAG_READ_WRITE) < 0)
{
printf("Failed to open output file! \n");
return -1;
}
/* Add the audio and video streams using the default format codecs
* and initialize the codecs. */
video_st = NULL;
audio_st = NULL;
if (fmt->video_codec != AV_CODEC_ID_NONE) {
video_st = add_stream(pFormatCtx, &pCodec, AV_CODEC_ID_H264);
}
if (fmt->audio_codec != AV_CODEC_ID_NONE) {
audio_st = add_stream(pFormatCtx, &aCodec, AV_CODEC_ID_MP3);
}
/* Now that all the parameters are set, we can open the audio and
* video codecs and allocate the necessary encode buffers. */
if (video_st)
[self open_video:pFormatCtx avcodec:pCodec avstream:video_st];
if (audio_st)
[self open_audio:pFormatCtx avcodec:aCodec avstream:audio_st];
// Show some Information
av_dump_format(pFormatCtx, 0, out_file, 1);
//Write File Header
avformat_write_header(pFormatCtx, NULL);
av_new_packet(&pkt, picture_size);
av_new_packet(&pkt2, picture_size);
AVCodecContext *c = video_st->codec;
y_size = c->width * c->height;
if (pFrame)
pFrame->pts = 0;
if(aFrame)
{
aFrame->pts = 0;
}
return 0;
}
static AVStream *add_stream(AVFormatContext *oc, AVCodec **codec, enum AVCodecID codec_id)
{
AVCodecContext *c;
AVStream *st;
/* find the encoder */
*codec = avcodec_find_encoder(codec_id);
if (!(*codec))
{
NSLog(#"Could not find encoder for '%s'\n",
avcodec_get_name(codec_id));
}
st = avformat_new_stream(oc, *codec);
if (!st)
{
NSLog(#"Could not allocate stream\n");
}
st->id = oc->nb_streams-1;
c = st->codec;
switch ((*codec)->type)
{
case AVMEDIA_TYPE_AUDIO:
c->codec_id = AV_CODEC_ID_MP3;
c->codec_type = AVMEDIA_TYPE_AUDIO;
c->channels = 1;
c->sample_fmt = AV_SAMPLE_FMT_S16P;
c->bit_rate = 128000;
c->sample_rate = 44100;
c->channel_layout = AV_CH_LAYOUT_MONO;
break;
case AVMEDIA_TYPE_VIDEO:
c->codec_id = AV_CODEC_ID_H264;
c->codec_type=AVMEDIA_TYPE_VIDEO;
/* Resolution must be a multiple of two. */
c->width = 720;
c->height = 1280;
/* timebase: This is the fundamental unit of time (in seconds) in terms
* of which frame timestamps are represented. For fixed-fps content,
* timebase should be 1/framerate and timestamp increments should be
* identical to 1. */
c->time_base.den = 30;
c->time_base.num = 1;
c->gop_size = 15; /* emit one intra frame every twelve frames at most */
c->pix_fmt = PIX_FMT_YUV420P;
c->max_b_frames = 0;
c->bit_rate = 3000000;
c->qmin = 10;
c->qmax = 51;
break;
default:
break;
}
/* Some formats want stream headers to be separate. */
if (oc->oformat->flags & AVFMT_GLOBALHEADER)
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
return st;
}
SampleBuffer will turn into H264 and pushed out RTMP Streaming
- (void)encoderToH264:(CMSampleBufferRef)sampleBuffer
{
CVPixelBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
if (CVPixelBufferLockBaseAddress(imageBuffer, 0) == kCVReturnSuccess)
{
UInt8 *bufferbasePtr = (UInt8 *)CVPixelBufferGetBaseAddress(imageBuffer);
UInt8 *bufferPtr = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer,0);
UInt8 *bufferPtr1 = (UInt8 *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer,1);
size_t buffeSize = CVPixelBufferGetDataSize(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t bytesrow0 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,0);
size_t bytesrow1 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,1);
size_t bytesrow2 = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer,2);
UInt8 *yuv420_data = (UInt8 *)malloc(width * height *3/ 2); // buffer to store YUV with layout YYYYYYYYUUVV
/* convert NV12 data to YUV420*/
UInt8 *pY = bufferPtr ;
UInt8 *pUV = bufferPtr1;
UInt8 *pU = yuv420_data + width*height;
UInt8 *pV = pU + width*height/4;
for(int i =0;i<height;i++)
{
memcpy(yuv420_data+i*width,pY+i*bytesrow0,width);
}
for(int j = 0;j<height/2;j++)
{
for(int i =0;i<width/2;i++)
{
*(pU++) = pUV[i<<1];
*(pV++) = pUV[(i<<1) + 1];
}
pUV+=bytesrow1;
}
//Read raw YUV data
picture_buf = yuv420_data;
pFrame->data[0] = picture_buf; // Y
pFrame->data[1] = picture_buf+ y_size; // U
pFrame->data[2] = picture_buf+ y_size*5/4; // V
int got_picture = 0;
// Encode
pFrame->width = 720;
pFrame->height = 1280;
pFrame->format = PIX_FMT_YUV420P;
AVCodecContext *c = video_st->codec;
int ret = avcodec_encode_video2(c, &pkt, pFrame, &got_picture);
if(ret < 0)
{
printf("Failed to encode! \n");
}
if (got_picture==1)
{
/* Compute current audio and video time. */
video_time = video_st ? video_st->pts.val * av_q2d(video_st->time_base) : 0.0;
pFrame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);
if(pkt.size != 0)
{
printf("Succeed to encode frame: %5lld\tsize:%5d\n", pFrame->pts, pkt.size);
pkt.stream_index = video_st->index;
ret = av_write_frame(pFormatCtx, &pkt);
av_free_packet(&pkt);
}
}
free(yuv420_data);
}
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
}
SampleBuffer will turn into MP3 and pushed out RTMP Streaming
-(void)encoderToMP3:(CMSampleBufferRef)sampleBuffer
{
CMSampleTimingInfo timing_info;
CMSampleBufferGetSampleTimingInfo(sampleBuffer, 0, &timing_info);
double pts=0;
double dts=0;
AVCodecContext *c;
int got_packet, ret;
c = audio_st->codec;
CMItemCount numSamples = CMSampleBufferGetNumSamples(sampleBuffer);
NSUInteger channelIndex = 0;
CMBlockBufferRef audioBlockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
size_t audioBlockBufferOffset = (channelIndex * numSamples * sizeof(SInt16));
size_t lengthAtOffset = 0;
size_t totalLength = 0;
SInt16 *samples = NULL;
CMBlockBufferGetDataPointer(audioBlockBuffer, audioBlockBufferOffset, &lengthAtOffset, &totalLength, (char **)(&samples));
const AudioStreamBasicDescription *audioDescription = CMAudioFormatDescriptionGetStreamBasicDescription(CMSampleBufferGetFormatDescription(sampleBuffer));
SwrContext *swr = swr_alloc();
int in_smprt = (int)audioDescription->mSampleRate;
av_opt_set_int(swr, "in_channel_layout", AV_CH_LAYOUT_MONO, 0);
av_opt_set_int(swr, "out_channel_layout", audio_st->codec->channel_layout, 0);
av_opt_set_int(swr, "in_channel_count", audioDescription->mChannelsPerFrame, 0);
av_opt_set_int(swr, "out_channel_count", 1, 0);
av_opt_set_int(swr, "out_channel_layout", audio_st->codec->channel_layout, 0);
av_opt_set_int(swr, "in_sample_rate", audioDescription->mSampleRate,0);
av_opt_set_int(swr, "out_sample_rate", audio_st->codec->sample_rate,0);
av_opt_set_sample_fmt(swr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
av_opt_set_sample_fmt(swr, "out_sample_fmt", audio_st->codec->sample_fmt, 0);
swr_init(swr);
uint8_t **input = NULL;
int src_linesize;
int in_samples = (int)numSamples;
ret = av_samples_alloc_array_and_samples(&input, &src_linesize, audioDescription->mChannelsPerFrame, in_samples, AV_SAMPLE_FMT_S16P, 0);
*input=(uint8_t*)samples;
uint8_t *output=NULL;
int out_samples = av_rescale_rnd(swr_get_delay(swr, in_smprt) +in_samples, (int)audio_st->codec->sample_rate, in_smprt, AV_ROUND_UP);
av_samples_alloc(&output, NULL, audio_st->codec->channels, out_samples, audio_st->codec->sample_fmt, 0);
in_samples = (int)numSamples;
out_samples = swr_convert(swr, &output, out_samples, (const uint8_t **)input, in_samples);
aFrame->nb_samples =(int) out_samples;
ret = avcodec_fill_audio_frame(aFrame, audio_st->codec->channels, audio_st->codec->sample_fmt,
(uint8_t *)output,
(int) out_samples *
av_get_bytes_per_sample(audio_st->codec->sample_fmt) *
audio_st->codec->channels, 1);
if (ret < 0)
{
fprintf(stderr, "Error fill audio frame: %s\n", av_err2str(ret));
}
aFrame->channel_layout = audio_st->codec->channel_layout;
aFrame->channels=audio_st->codec->channels;
aFrame->sample_rate= audio_st->codec->sample_rate;
if (timing_info.presentationTimeStamp.timescale!=0)
pts=(double) timing_info.presentationTimeStamp.value/timing_info.presentationTimeStamp.timescale;
aFrame->pts = pts*audio_st->time_base.den;
aFrame->pts = av_rescale_q(aFrame->pts, audio_st->time_base, audio_st->codec->time_base);
ret = avcodec_encode_audio2(c, &pkt2, aFrame, &got_packet);
if (ret < 0)
{
fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));
}
swr_free(&swr);
if (got_packet)
{
pkt2.stream_index = audio_st->index;
// Write the compressed frame to the media file.
ret = av_interleaved_write_frame(pFormatCtx, &pkt2);
if (ret != 0)
{
fprintf(stderr, "Error while writing audio frame: %s\n", av_err2str(ret));
av_free_packet(&pkt2);
}
}
}
Soon "Broken pipe" problem occurs after execution.
PTS is currently feeling is not adjusted, but do not know how to adjust the PTS.
2016-03-09 16:57:41.058 PoliceCamPlayer[1004:193465] recordVideo....
[libx264 # 0x12f8b6e00] using cpu capabilities: ARMv8 NEON
[libx264 # 0x12f8b6e00] profile Constrained Baseline, level 3.1
[libx264 # 0x12f8b6e00] 264 - core 148 - H.264/MPEG-4 AVC codec - Copyleft 2003-2016 - http://www.videolan.org/x264.html - options: cabac=0 ref=1 deblock=1:0:0 analyse=0x1:0x111 me=hex subme=2 psy=1 psy_rd=1.00:0.00 mixed_ref=0 me_range=16 chroma_me=1 trellis=0 8x8dct=0 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=0 threads=2 lookahead_threads=2 sliced_threads=1 slices=2 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=0 weightp=0 keyint=15 keyint_min=1 scenecut=40 intra_refresh=0 rc=abr mbtree=0 bitrate=3000 ratetol=1.0 qcomp=0.60 qpmin=25 qpmax=51 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, flv, to 'rtmp://XXX.XX.XXX.XX/myapp/jackal':
Stream #0:0: Video: h264 (libx264), yuv420p, 720x1280, q=25-51, 3000 kb/s, 23 tbc
Stream #0:1: Audio: mp3 (libmp3lame), 44100 Hz, mono, s16p, 64 kb/s
[flv # 0x12f8b5400] Using AVStream.codec.time_base as a timebase hint to the muxer is deprecated. Set AVStream.time_base instead.
[flv # 0x12f8b5400] Using AVStream.codec.time_base as a timebase hint to the muxer is deprecated. Set AVStream.time_base instead.
[libx264 # 0x12f8b6e00] Provided packet is too small, needs to be 33468
Failed to encode!
Audio_pts:4154432515 pts_time:4.15443e+06 dts:4154432515 dts_time:4.15443e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:43 pts_time:0.043 dts:43 dts_time:0.043 duration:0 duration_time:0 stream_index:0
Audio_pts:4154433667 pts_time:4.15443e+06 dts:4154433667 dts_time:4.15443e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154434854 pts_time:4.15443e+06 dts:4154434854 dts_time:4.15443e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:86 pts_time:0.086 dts:86 dts_time:0.086 duration:0 duration_time:0 stream_index:0
Audio_pts:4154435996 pts_time:4.15444e+06 dts:4154435996 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154437138 pts_time:4.15444e+06 dts:4154437138 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:129 pts_time:0.129 dts:129 dts_time:0.129 duration:0 duration_time:0 stream_index:0
Audio_pts:4154438281 pts_time:4.15444e+06 dts:4154438281 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:172 pts_time:0.172 dts:172 dts_time:0.172 duration:0 duration_time:0 stream_index:0
Audio_pts:4154439467 pts_time:4.15444e+06 dts:4154439467 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:215 pts_time:0.215 dts:215 dts_time:0.215 duration:0 duration_time:0 stream_index:0
Audio_pts:4154440609 pts_time:4.15444e+06 dts:4154440609 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154441752 pts_time:4.15444e+06 dts:4154441752 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:258 pts_time:0.258 dts:258 dts_time:0.258 duration:0 duration_time:0 stream_index:0
Audio_pts:4154442884 pts_time:4.15444e+06 dts:4154442884 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154444071 pts_time:4.15444e+06 dts:4154444071 dts_time:4.15444e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:301 pts_time:0.301 dts:301 dts_time:0.301 duration:0 duration_time:0 stream_index:0
Audio_pts:4154445213 pts_time:4.15445e+06 dts:4154445213 dts_time:4.15445e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154446355 pts_time:4.15445e+06 dts:4154446355 dts_time:4.15445e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:344 pts_time:0.344 dts:344 dts_time:0.344 duration:0 duration_time:0 stream_index:0
Audio_pts:4154447498 pts_time:4.15445e+06 dts:4154447498 dts_time:4.15445e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:387 pts_time:0.387 dts:387 dts_time:0.387 duration:0 duration_time:0 stream_index:0
Audio_pts:4154448640 pts_time:4.15445e+06 dts:4154448640 dts_time:4.15445e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154449826 pts_time:4.15445e+06 dts:4154449826 dts_time:4.15445e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:430 pts_time:0.43 dts:430 dts_time:0.43 duration:0 duration_time:0 stream_index:0
Audio_pts:4154450969 pts_time:4.15445e+06 dts:4154450969 dts_time:4.15445e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154452101 pts_time:4.15445e+06 dts:4154452101 dts_time:4.15445e+06 duration:1152 duration_time:1.152 stream_index:1
...................
...................
...................
Video_pts:4343 pts_time:4.343 dts:4343 dts_time:4.343 duration:0 duration_time:0 stream_index:0
Audio_pts:4154622619 pts_time:4.15462e+06 dts:4154622619 dts_time:4.15462e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:4386 pts_time:4.386 dts:4386 dts_time:4.386 duration:0 duration_time:0 stream_index:0
Audio_pts:4154623761 pts_time:4.15462e+06 dts:4154623761 dts_time:4.15462e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154624903 pts_time:4.15462e+06 dts:4154624903 dts_time:4.15462e+06 duration:1152 duration_time:1.152 stream_index:1
Audio_pts:4154626090 pts_time:4.15463e+06 dts:4154626090 dts_time:4.15463e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:4429 pts_time:4.429 dts:4429 dts_time:4.429 duration:0 duration_time:0 stream_index:0
Audio_pts:4154627222 pts_time:4.15463e+06 dts:4154627222 dts_time:4.15463e+06 duration:1152 duration_time:1.152 stream_index:1
Video_pts:4472 pts_time:4.472 dts:4472 dts_time:4.472 duration:0 duration_time:0 stream_index:0
Error while writing audio frame: Broken pipe
Audio_pts:4154628365 pts_time:4.15463e+06 dts:4154628365 dts_time:4.15463e+06 duration:1152 duration_time:1.152 stream_index:1
Error while writing audio frame: Broken pipe
Audio_pts:4154629507 pts_time:4.15463e+06 dts:4154629507 dts_time:4.15463e+06 duration:1152 duration_time:1.152 stream_index:1
Error while writing audio frame: Broken pipe
Audio_pts:4154630693 pts_time:4.15463e+06 dts:4154630693 dts_time:4.15463e+06 duration:1152 duration_time:1.152 stream_index:1
Error while writing audio frame: Broken pipe
Audio_pts:4154631836 pts_time:4.15463e+06 dts:4154631836 dts_time:4.15463e+06 duration:1152 duration_time:1.152 stream_index:1
Error while writing audio frame: Broken pipe
Audio_pts:4154632978 pts_time:4.15463e+06 dts:4154632978 dts_time:4.15463e+06 duration:1152 duration_time:1.152 stream_index:1
.......................
.......................
.......................
2016-03-09 16:57:49.345 PoliceCamPlayer[1004:193465] stopRecord!!!
Video_pts:7783 pts_time:7.783 dts:7783 dts_time:7.783 duration:0 duration_time:0 stream_index:0
[flv # 0x12f8b5400] Failed to update header with correct duration.
[flv # 0x12f8b5400] Failed to update header with correct filesize.
[libx264 # 0x12f8b6e00] frame I:28 Avg QP:25.36 size: 24181
[libx264 # 0x12f8b6e00] frame P:154 Avg QP:25.34 size: 6603
[libx264 # 0x12f8b6e00] mb I I16..4: 80.9% 0.0% 19.1%
[libx264 # 0x12f8b6e00] mb P I16..4: 5.9% 0.0% 0.2% P16..4: 28.2% 4.4% 1.0% 0.0% 0.0% skip:60.2%
[libx264 # 0x12f8b6e00] final ratefactor: 16.70
[libx264 # 0x12f8b6e00] coded y,uvDC,uvAC intra: 35.8% 9.3% 0.4% inter: 8.8% 1.6% 0.0%
[libx264 # 0x12f8b6e00] i16 v,h,dc,p: 28% 26% 26% 21%
[libx264 # 0x12f8b6e00] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 13% 26% 25% 3% 7% 4% 5% 3% 13%
[libx264 # 0x12f8b6e00] i8c dc,h,v,p: 85% 9% 5% 0%
[libx264 # 0x12f8b6e00] kb/s:1712.63
Increase PTS by amount of samples that you are sending to encoder.
Also, don't forget to rescale timings from your audio stream to output format context.
So, the fixes are:
audioFrame->pts = audioSamplesCounter; // starting from zero
Then after encoding (avcodec_encode_audio2) increase counter by amount of samples in frame that you have sent to encoder (in your case this will be not the amount you've got from CMSampleBuffer, but the one after resampling by SWR - "out_samples"):
audioSamplesCounter += audioFrame->nb_samples;
And right before writing to an media output file rescale timings:
av_packet_rescale_ts(&audioPacket,
audioStream->codec->time_base,
outputFormatContext->streams[audioStream->index]->time_base);
Also, I'd like recommend you to optimize approaches you using device's resources.
Create contexts for rescaling/resampling once and reuse them.
Allocate buffers for audio and video as soon as your stream starts or when first CMSampleBufferRef arrives. The size will not change until restarting stream/session. It will be huge improvement for performance & memory consumption.
Use hardware acceleration when it's possible.
Do not forget to free any allocated arrays & contexts.
Hope it helps you :)
Related
I made the conversion between FFmpeg's avframe and OpenCV's mat. But the following code doesn't convert the mat format to avframe format correctly. The first part converts avframe to mat format and the second part converts mat to avframe format.
Here is my source code:
AVFrame* ProcessFrame(AVFrame *frame, int stream_index)
{
//first part
AVStream *in_stream = ifmt_ctx->streams[stream_index];
AVCodecContext *pCodecCtx = in_stream->codec;
AVFrame *pFrameRGB = NULL;
struct SwsContext * img_convert_ctx = NULL;
if(img_convert_ctx == NULL){
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
}
pFrameRGB = av_frame_alloc();
int size = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
uint8_t *out_bufferRGB = (uint8_t *)av_malloc(size);
avpicture_fill((AVPicture *)pFrameRGB, out_bufferRGB, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
sws_scale(img_convert_ctx, frame->data, frame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
Mat imageFrame = Mat(pCodecCtx->height, pCodecCtx->width, CV_8UC3, out_bufferRGB);
delete[] out_bufferRGB;
///////////////////////////////////////////////////////////
//second part starts
avpicture_fill((AVPicture *)pFrameRGB, imageFrame.data,AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
struct SwsContext * convert_ctx = NULL;
if(convert_ctx == NULL){
convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
}
AVFrame *srcFrame = av_frame_alloc();
size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
uint8_t *out_buffer = (uint8_t *)av_malloc(size);
avpicture_fill((AVPicture *)srcFrame, out_buffer, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
sws_scale(convert_ctx, pFrameRGB->data, pFrameRGB->linesize, 0, pCodecCtx->height, srcFrame->data, srcFrame->linesize);
delete[] out_buffer;
av_free(pFrameRGB);
srcFrame->width = frame->width;
srcFrame->height = frame->height;
srcFrame->format = frame->format;
av_frame_copy_props(srcFrame, frame);
return srcFrame;
}
Finally, I remove the del statement to make it work.
AVFrame* ProcessFrame(AVFrame *frame, int stream_index)
{
//first part
AVStream *in_stream = ifmt_ctx->streams[stream_index];
AVCodecContext *pCodecCtx = in_stream->codec;
AVFrame *pFrameRGB = NULL;
struct SwsContext * img_convert_ctx = NULL;
if(img_convert_ctx == NULL){
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_BGR24, SWS_BICUBIC, NULL, NULL, NULL);
}
pFrameRGB = av_frame_alloc();
int size = avpicture_get_size(AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
uint8_t *out_bufferRGB = (uint8_t *)av_malloc(size);
avpicture_fill((AVPicture *)pFrameRGB, out_bufferRGB, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
sws_scale(img_convert_ctx, frame->data, frame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
Mat imageFrame = Mat(pCodecCtx->height, pCodecCtx->width, CV_8UC3, out_bufferRGB);
///////////////////////////////////////////////////////////
//second part starts
avpicture_fill((AVPicture *)pFrameRGB, imageFrame.data,AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height);
struct SwsContext * convert_ctx = NULL;
if(convert_ctx == NULL){
convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
}
AVFrame *srcFrame = av_frame_alloc();
size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
uint8_t *out_buffer = (uint8_t *)av_malloc(size);
avpicture_fill((AVPicture *)srcFrame, out_buffer, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
sws_scale(convert_ctx, pFrameRGB->data, pFrameRGB->linesize, 0, pCodecCtx->height, srcFrame->data, srcFrame->linesize);
av_free(pFrameRGB);
srcFrame->width = frame->width;
srcFrame->height = frame->height;
srcFrame->format = frame->format;
av_frame_copy_props(srcFrame, frame);
return srcFrame;
}
I need to convert CMSampleBuffer to Data format. I am using one Third party framework for audio related task. That framework gives me the streaming (i.e Real Time audio) audio in CMSampleBuffer object.
Like this:
func didAudioStreaming(audioSample: CMSampleBuffer!) {
//Here I need to conver this to Data format.
//Because I am using GRPC framework for Audio Recognization,
}
Please provide me the steps to convert the CMSampleBuffer to Data.
FYI
let formatDesc:CMFormatDescription? = CMSampleBufferGetFormatDescription(audioSample)
<CMAudioFormatDescription 0x17010d890 [0x1b453ebb8]> {
mediaType:'soun'
mediaSubType:'lpcm'
mediaSpecific: {
ASBD: {
mSampleRate: 16000.000000
mFormatID: 'lpcm'
mFormatFlags: 0xc
mBytesPerPacket: 2
mFramesPerPacket: 1
mBytesPerFrame: 2
mChannelsPerFrame: 1
mBitsPerChannel: 16 }
cookie: {(null)}
ACL: {(null)}
FormatList Array: {(null)}
}
extensions: {(null)}
}
Try below code to convert CMSampleBuffer to NSData.
let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
CVPixelBufferLockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer!)
let height = CVPixelBufferGetHeight(imageBuffer!)
let src_buff = CVPixelBufferGetBaseAddress(imageBuffer!)
let data = NSData(bytes: src_buff, length: bytesPerRow * height)
CVPixelBufferUnlockBaseAddress(imageBuffer!, CVPixelBufferLockFlags(rawValue: 0))
EDIT-
For AudioBuffer use below code -
var audioBufferList = AudioBufferList()
var data = Data()
var blockBuffer : CMBlockBuffer?
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, nil, &audioBufferList, MemoryLayout<AudioBufferList>.size, nil, nil, 0, &blockBuffer)
let buffers = UnsafeBufferPointer<AudioBuffer>(start: &audioBufferList.mBuffers, count: Int(audioBufferList.mNumberBuffers))
for audioBuffer in buffers {
let frame = audioBuffer.mData?.assumingMemoryBound(to: UInt8.self)
data.append(frame!, count: Int(audioBuffer.mDataByteSize))
}
Using CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer will require to call at some point CFRelease(blockBuffer) because the buffer is retained and if not released the pool of buffers will become eventually empty and no new CMSampleBuffer will be generated.
I'd suggest to get directly the data using the following:
CMBlockBufferRef blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer);
size_t lengthAtOffset;
size_t totalLength;
char *data;
CMBlockBufferGetDataPointer(blockBuffer, 0, &lengthAtOffset, &totalLength, &data);
NSData *audioData = [NSData dataWithBytes:data length:totalLength];
I recevie audio data and size from outside, the audio appears to be linear PCM, signed int16, but when recording this using an AssetWriter it saves to the audio file highly distorted and higher pitch.
#define kSamplingRate 16000
#define kNumberChannels 1
UInt32 framesAlreadyWritten = 0;
-(AudioStreamBasicDescription) getAudioFormat {
AudioStreamBasicDescription format;
format.mSampleRate = kSamplingRate;
format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
format.mChannelsPerFrame = 1; // mono
format.mBitsPerChannel = 16;
format.mBytesPerFrame = sizeof(SInt16);
format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
format.mReserved = 0;
return format;
}
- (CMSampleBufferRef)createAudioSample:(const void *)audioData frames: (UInt32)len {
AudioStreamBasicDescription asbd = [self getAudioFormat];
CMSampleBufferRef buff = NULL;
static CMFormatDescriptionRef format = NULL;
OSStatus error = 0;
if(format == NULL) {
AudioChannelLayout acl;
bzero(&acl, sizeof(acl));
acl.mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
error = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &asbd, sizeof(acl), &acl, 0, NULL, NULL, &format);
}
CMTime duration = CMTimeMake(1, kSamplingRate);
CMTime pts = CMTimeMake(framesAlreadyWritten, kSamplingRate);
NSLog(#"-----------pts");
CMTimeShow(pts);
CMSampleTimingInfo timing = {duration , pts, kCMTimeInvalid };
error = CMSampleBufferCreate(kCFAllocatorDefault, NULL, false, NULL, NULL, format, len, 1, &timing, 0, NULL, &buff);
framesAlreadyWritten += len;
if (error) {
NSLog(#"CMSampleBufferCreate returned error: %ld", (long)error);
return NULL;
}
AudioBufferList audioBufferList;
audioBufferList.mNumberBuffers = 1;
audioBufferList.mBuffers[0].mNumberChannels = asbd.mChannelsPerFrame;
audioBufferList.mBuffers[0].mDataByteSize = (UInt32)(number_of_frames * audioFormat.mBytesPerFrame);
audioBufferList.mBuffers[0].mData = audioData;
error = CMSampleBufferSetDataBufferFromAudioBufferList(buff, kCFAllocatorDefault, kCFAllocatorDefault, 0, &audioBufferList);
if(error) {
NSLog(#"CMSampleBufferSetDataBufferFromAudioBufferList returned error: %ld", (long)error);
return NULL;
}
return buff;
}
Not sure why you're dividing len by two, but your time should progress instead of being constant, something like
CMTime time = CMTimeMake(framesAlreadyWritten , kSamplingRate);
I am developing Voip application with Opus for iOS (Objective-C and C++).
It works fine with 8000, 12000, 24000 and 48000 sampling rate except with 16000, where the application crashes on opus_encode method.
Here is what i am doing:
m_oAudioSession = [AVAudioSession sharedInstance];
[m_oAudioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&m_oError];
[m_oAudioSession setMode:AVAudioSessionModeVoiceChat error:&m_oError];
[m_oAudioSession setPreferredSampleRate:VOIP_AUDIO_DRIVER_DEFAULT_SAMPLE_RATE error:&m_oError];
[m_oAudioSession setPreferredInputNumberOfChannels:VOIP_AUDIO_DRIVER_DEFAULT_INPUT_CHANNELS error:&m_oError];
[m_oAudioSession setPreferredOutputNumberOfChannels:VOIP_AUDIO_DRIVER_DEFAULT_OUTPUT_CHANNELS error:&m_oError];
[m_oAudioSession setPreferredIOBufferDuration:VOIP_AUDIO_DRIVER_DEFAULT_BUFFER_DURATION error:&m_oError];
[m_oAudioSession setActive:YES error:&m_oError];
Constants:
VOIP_AUDIO_DRIVER_DEFAULT_SAMPLE_RATE is 16000
VOIP_AUDIO_DRIVER_DEFAULT_INPUT_CHANNELS is 1
VOIP_AUDIO_DRIVER_DEFAULT_OUTPUT_CHANNELS is 1
VOIP_AUDIO_DRIVER_DEFAULT_BUFFER_DURATION is 0.02
VOIP_AUDIO_DRIVER_FRAMES_PER_PACKET is 1
After that i am using a real sampling rate and buffer duration from m_oAudioSession.sampleRate and m_oAudioSession.IOBufferDuration. They are set into m_fSampleRate and m_fBufferDuration variables.
The configurations are:
//Describes audio component:
m_sAudioDescription.componentType = kAudioUnitType_Output;
m_sAudioDescription.componentSubType = kAudioUnitSubType_VoiceProcessingIO/*kAudioUnitSubType_RemoteIO*/;
m_sAudioDescription.componentFlags = 0;
m_sAudioDescription.componentFlagsMask = 0;
m_sAudioDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
m_sAudioFormat.mSampleRate = m_fSampleRate;
m_sAudioFormat.mFormatID = kAudioFormatLinearPCM;
m_sAudioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
m_sAudioFormat.mFramesPerPacket = VOIP_AUDIO_DRIVER_FRAMES_PER_PACKET;
m_sAudioFormat.mChannelsPerFrame = VOIP_AUDIO_DRIVER_DEFAULT_INPUT_CHANNELS;
m_sAudioFormat.mBitsPerChannel = (UInt32)(8 * m_iBytesPerSample);
m_sAudioFormat.mBytesPerFrame = (UInt32)((m_sAudioFormat.mBitsPerChannel / 8) * m_sAudioFormat.mChannelsPerFrame);
m_sAudioFormat.mBytesPerPacket = m_sAudioFormat.mBytesPerFrame * m_sAudioFormat.mFramesPerPacket;
m_sAudioFormat.mReserved = 0;
The calculations i make are:
m_iBytesPerSample = sizeof(/*AudioSampleType*/SInt16);
//Calculating buffer size:
int samplesPerFrame = (int)(m_fBufferDuration * m_fSampleRate) + 1;
m_iBufferSizeBytes = samplesPerFrame * m_iBytesPerSample;
//Allocating input buffer:
UInt32 inputBufferListSize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * m_sAudioFormat.mChannelsPerFrame);
m_sInputBuffer = (AudioBufferList *)VoipAlloc(inputBufferListSize);
m_sInputBuffer->mNumberBuffers = m_sAudioFormat.mChannelsPerFrame;
//Pre-mallocating buffers for AudioBufferLists
for(VoipUInt32 tmp_int1 = 0; tmp_int1 < m_sInputBuffer->mNumberBuffers; tmp_int1++)
{
m_sInputBuffer->mBuffers[tmp_int1].mNumberChannels = VOIP_AUDIO_DRIVER_DEFAULT_INPUT_CHANNELS;
m_sInputBuffer->mBuffers[tmp_int1].mDataByteSize = (UInt32)m_iBufferSizeBytes;
m_sInputBuffer->mBuffers[tmp_int1].mData = VoipAlloc(m_iBufferSizeBytes);
memset(m_sInputBuffer->mBuffers[tmp_int1].mData, 0, m_iBufferSizeBytes);
}
The reading and writing from audio unit are done using m_sInputBuffer.
Here is the Opus creation:
m_oEncoder = opus_encoder_create(m_iSampleRate, m_iNumberOfChannels, VOIP_AUDIO_CODECS_OPUS_APPLICATION_TYPE, &_error);
if (_error < 0)
{
fprintf(stderr, "VoipAudioCodecs error: failed to create an encoder: %s\n", opus_strerror(_error));
return;
}
_error = opus_encoder_ctl(m_oEncoder, OPUS_SET_BITRATE(VOIP_AUDIO_CODECS_OPUS_BITRATE));
if (_error < 0)
{
fprintf(stderr, "VoipAudioCodecs error: failed to set the bitrate: %s\n", opus_strerror(_error));
return;
}
m_oDecoder = opus_decoder_create(m_iSampleRate, m_iNumberOfChannels, &_error);
if (_error < 0)
{
fprintf(stderr, "VoipAudioCodecs error: failed to create a decoder: %s\n", opus_strerror(_error));
return;
}
Opus configurations are:
VOIP_AUDIO_CODECS_OPUS_BITRATE is OPUS_BITRATE_MAX
//64000 //70400 //84800 //112000
VOIP_AUDIO_CODECS_OPUS_APPLICATION_TYPE is OPUS_APPLICATION_VOIP
//OPUS_APPLICATION_AUDIO
VOIP_AUDIO_CODECS_OPUS_MAX_FRAME_SIZE is 5760
//Minimum: (120ms; 5760 for 48kHz)
VOIP_AUDIO_CODECS_OPUS_BYTES_SIZE is 960
//120, 240, 480, 960, 1920, 2880
When i encode and decode i use these methods:
Encode_Opus(VoipInt16* rawSamples, int rawSamplesSize)
{
unsigned char encodedData[m_iMaxPacketSize];
VoipInt32 bytesEncoded;
int frameSize = rawSamplesSize / m_iBytesPerSample;
bytesEncoded = opus_encode(m_oEncoder, rawSamples, frameSize, encodedData, m_iMaxPacketSize);
if (bytesEncoded < 0)
{
fprintf(stderr, "VoipAudioCodecs error: encode failed: %s\n", opus_strerror(bytesEncoded));
return nullptr;
}
sVoipAudioCodecOpusEncoded* resultStruct = (sVoipAudioCodecOpusEncoded* )VoipAlloc(sizeof(sVoipAudioCodecOpusEncoded));
resultStruct->m_data = (unsigned char*)VoipAlloc(bytesEncoded);
memcpy(resultStruct->m_data, encodedData, bytesEncoded);
resultStruct->m_dataSize = bytesEncoded;
return resultStruct;
}
Decode_Opus(void* encodedSamples, VoipInt32 encodedSamplesSize)
{
VoipInt16 decodedPacket[VOIP_AUDIO_CODECS_OPUS_MAX_FRAME_SIZE];
int _frameSize = opus_decode(m_oDecoder, (const unsigned char*)encodedSamples, encodedSamplesSize, decodedPacket, VOIP_AUDIO_CODECS_OPUS_MAX_FRAME_SIZE, 0);
if (_frameSize < 0)
{
fprintf(stderr, "VoipAudioCodecs error: decoder failed: %s\n", opus_strerror(_frameSize));
return nullptr;
}
size_t frameSize = (size_t)_frameSize;
sVoipAudioCodecOpusDecoded* resultStruct = (sVoipAudioCodecOpusDecoded* )VoipAlloc(sizeof(sVoipAudioCodecOpusDecoded));
resultStruct->m_data = (VoipInt16*)VoipAlloc(frameSize * m_iBytesPerSample);
memcpy(resultStruct->m_data, decodedPacket, (frameSize * m_iBytesPerSample));
resultStruct->m_dataSize = frameSize * m_iBytesPerSample;
return resultStruct;
}
When the app should send data:
VoipUInt32 itemsForProcess = inputAudioQueue->getItemCount();
for (int tmp_queueItems = 0; tmp_queueItems < itemsForProcess; tmp_queueItems++)
{
sVoipQueue* tmp_samples = inputAudioQueue->popItem();
m_oCircularTempInputBuffer->writeDataToBuffer(tmp_samples->m_pData, tmp_samples->m_iDataSize);
while (void* tmp_buffer = m_oCircularTempInputBuffer->readDataFromBuffer(VOIP_AUDIO_CODECS_OPUS_BYTES_SIZE))
{
sVoipAudioCodecOpusEncoded* encodedSamples = Encode_Opus((VoipInt16*)tmp_buffer, VOIP_AUDIO_CODECS_OPUS_BYTES_SIZE);
//Then packeting and the real sending using tcp socket…
}
//Rest of the code…
}
Here is the reading:
sVoipAudioCodecOpusDecoded* decodedSamples = Decode_Opus(inputPacket->m_pPacketData, (VoipInt32)inputPacket->m_iPacketSize);
if (decodedSamples != nullptr)
{
m_oCircularTempOutputBuffer->writeDataToBuffer(decodedSamples->m_data, decodedSamples->m_dataSize);
VoipFree((void**)&decodedSamples->m_data);
VoipFree((void**)&decodedSamples);
}
while (void* tmp_buffer = m_oCircularTempOutputBuffer->readDataFromBuffer(m_iBufferSizeBytes))
{
outputAudioQueue->pushItem(tmp_buffer, m_iBufferSizeBytes);
}
inputAudioQueue is queue with recorded data from my audio unit’s callback.
outputAudioQueue is a queue used from my audio unit’s callback to play the sound.
m_iMaxPacketSize is the same as m_iBufferSizeBytes.
My questions are:
I was wondering, are my calculations correct?
And if not, how can i improve them?
Do you see any mistake into the code?
Do you have a suggestion for fixing the crash bug on opus_encode method when the sampling rate is set to 16000?
Thank you in advance.
PS. I made some tests with sampling rate on 16000 and found this: If i use this formula: frame_duration = frame_size / sample rate, and if i set frame_duration to preferedIOBufferDuration: 120 / 16000 = 0.0075 //AVAudioSession sets 0.008000 —— Crashes
240 / 16000 = 0.015 //AVAudioSession sets 0.016000 —— Crashes
480 / 16000 = 0.03 //AVAudioSession sets 0.032000 —— Crashes
960 / 16000 = 0.06 //AVAudioSession sets 0.064000 —— Crashes
1920 / 16000 = 0.12 //AVAudioSession sets 0.128000 —— Works
2880 / 16000 = 0.18 //AVAudioSession sets 0.128000 —— CrashesThen i found that there is no encoder crash with sampling rate 16000 and preferredIOBufferDuration 0.12(1920), where AVAudioSession sets 0.128000. So it works only in this case.
Any ideas ?
I am writing a IOS App which will decode a H.264 frame and render using AVSampleBufferDisplayLayer. I have already modified the frame to not have the NAL start code but have a 4 byte NAL size. This has been verified.
But all i see is a white frame in my IOS simulator, No error; is there a possibility to dump the decoded frame and verify? Any other debug points will really help.
#implementation DecodeClass
- (void) viewDidLoad {
}
/* method to decode and render a frame */
- (void)decodeFrame{
NSLog(#"Decode Start");
/* local variable declaration */
//OSStatus status;
size_t spsSize, ppsSize,dataLen;
//_frameSize = 320*240*1.5;
uint8_t sps[] = {0x67, 0x42, 0xC0, 0x0D, 0x96, 0x64, 0x0A, 0x0F, 0xDF, 0xF8, 0x00, 0x20, 0x00, 0x18, 0x80, 0x00,
0x00, 0x7D, 0x00, 0x00, 0x0B, 0xB5, 0x47, 0x8A, 0x15, 0x50};
uint8_t pps[] = {0x68, 0xCE, 0x32, 0xC8};
const uint8_t* props[] = {sps, pps};
spsSize = (sizeof(sps)/sizeof(uint8_t));
ppsSize = (sizeof(pps)/sizeof(uint8_t));
const size_t sizes[] = {spsSize,ppsSize};
FILE* pFile;
int result;
pFile = fopen("/Documents/input_mod1.264","r");
fseeko(pFile, 0, SEEK_END);
unsigned long fileSize = ftello(pFile);
fseek(pFile, 0, SEEK_SET);
_dataBuf = (uint8_t*)malloc(sizeof(uint8_t) * (fileSize));
memset(_dataBuf,0,sizeof(uint8_t) * (fileSize));
if (pFile ){
result = fread(_dataBuf,sizeof(uint8_t),fileSize,pFile);
fclose(pFile);
}
else
NSLog(#"Can't open file");
[self MUX_Modify_AVC_Start_Code:_dataBuf size:&fileSize Header:false];
dataLen = fileSize;
//construct h.264 parameter set
CMVideoFormatDescriptionRef formatDesc;
OSStatus formatCreateResult = CMVideoFormatDescriptionCreateFromH264ParameterSets(kCFAllocatorDefault, 2, props, sizes, 4, &formatDesc);
if (formatCreateResult)
{
NSLog(#"construct CMVideoFormatDescriptionCreateFromH264ParameterSets Failed :%ld",(long)formatCreateResult);
}
//construct cmBlockbuffer .
CMBlockBufferRef blockBufferOut = nil;
CMBlockBufferCreateEmpty (0,0,kCMBlockBufferAlwaysCopyDataFlag, &blockBufferOut);
CMBlockBufferAppendMemoryBlock(blockBufferOut,
_dataBuf,
dataLen,
NULL,
NULL,
0,
dataLen,
kCMBlockBufferAlwaysCopyDataFlag);
//construct cmsamplebuffer ok
size_t sampleSizeArray[1] = {0};
sampleSizeArray[0] = CMBlockBufferGetDataLength(blockBufferOut);
CMSampleTimingInfo tmInfos[1] = {
{CMTimeMake(5,1), CMTimeMake(5,1), CMTimeMake(5,1)}
};
CMSampleBufferRef sampBuf = nil;
formatCreateResult = CMSampleBufferCreate(kCFAllocatorDefault,
blockBufferOut,
YES,
NULL,
NULL,
formatDesc,
1,
1,
tmInfos,
1,
sampleSizeArray,
&sampBuf);
NSLog(#"Decode End :: Construct CMSampleBufferRef value of formatCreateResult is %d", formatCreateResult);
if(!_dspLayer)
{
_dspLayer = [[AVSampleBufferDisplayLayer alloc]init];
[_dspLayer setFrame:CGRectMake(0,0,320,240)];
_dspLayer.bounds = CGRectMake(0, 0, 300, 300);
_dspLayer.videoGravity = AVLayerVideoGravityResizeAspect;
_dspLayer.position = CGPointMake(500, 500);
_dspLayer.backgroundColor = [UIColor blueColor].CGColor;
CMTimebaseRef tmBase = nil;
CMTimebaseCreateWithMasterClock(NULL,CMClockGetHostTimeClock(),&tmBase);
_dspLayer.controlTimebase = tmBase;
CMTimebaseSetTime(_dspLayer.controlTimebase, kCMTimeZero);
CMTimebaseSetRate(_dspLayer.controlTimebase, 1.0);
[self.layerView.layer addSublayer:_dspLayer];
}
//put to AVSampleBufferdisplayLayer,just one frame.
if([self.dspLayer isReadyForMoreMediaData])
{
[self.dspLayer enqueueSampleBuffer:sampBuf];
}
[self.dspLayer setNeedsDisplay];
}
-(void)MUX_Modify_AVC_Start_Code:(uint8_t*)pData size:(uint32_t *)nSize Header:(bool)bHeader{
....
}
-(uint32_t)MUX_FindNextPattern:(uint8_t*)streamBuf buffSize:(uint32_t)bufSize startCode:(uint32_t)startcode{
....
}
- (void)dealloc{
//free(_dataBuf);
}
#end
int main(int argc, char * argv[]) {
//[decodeClass release];
#autoreleasepool {
DecodeClass *decodeClass = [[DecodeClass alloc]init];
[decodeClass decodeFrame];
decodeClass = nil;
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}