ios直播推流每秒能达到30帧,比安卓要强,视频采用软编码的话手机会发烫,得采用码编码,播放视频采用opengl渲染。

 

  ffmpeg初始化代码如下:

 int init_Code(int width, int height, const char *out_path) {
av_log_set_callback(custom_log);
//avcodec_register_all();
av_register_all();
avformat_network_init();
avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path); //Open output URL,set before avformat_write_header() for muxing
AVOutputFormat * ofmt = ofmt_ctx->oformat;
if (!(ofmt->flags & AVFMT_NOFILE)) { //Open output URL
if (avio_open(&ofmt_ctx->pb, out_path, AVIO_FLAG_READ_WRITE) < ) {
return -;
}
}
if (isAudio == ) {
if (init_audio_Code() != )//初始化 音频参数
return -;
}
if (isVideo == ) {
if (init_video_code(width, height) != )//初始化 视频参数
return -;
}
av_dump_format(ofmt_ctx, , out_path, );
if (avformat_write_header(ofmt_ctx, NULL) < ) { //Write file header
//LOGE("Error occurred when opening output file\n");
return -;
} start_thread_encode(); //开始编码
return ;
}

  

  视频硬编码:

 /* 视频 硬编码**/
int encodeVideo_h264(uint8_t* in, int64_t time, int size, int keyframe) {
int ret;
// 定义AVPacket对象后,请使用av_init_packet进行初始化
av_init_packet(&video_pkt);
//av_new_packet(&video_pkt,size);
video_pkt.stream_index = video_st->index;
video_pkt.data = in; video_pkt.size = size;
video_pkt.pos = -;
ptsPacket(video_st, &video_pkt, time);
if (video_pkt.buf != NULL) {
video_pkt.buf->data = in;
video_pkt.buf->size = size;
}
video_pkt.flags = keyframe;
if (keyframe == ) {
//LOGE("硬编码-关键帧: %lld", time);
} ret = av_interleaved_write_frame(ofmt_ctx, &video_pkt);
if (ret != ) {
printf("----encodeVideo--encodeVideo -ret: %d ", ret);
//LOGE("----encodeVideo--encodeVideo -ret: %d ", ret);
}
av_free_packet(&video_pkt); return ;
}

  音频硬编码:

 /* 音频 硬编码**/
int encodeAudio_AAC(uint8_t* in, int64_t time, int size) {
if (isAudio == )
return ;
av_init_packet(&audio_pkt);
int got_frame = ;
audio_pkt.stream_index = audio_st->index; //标识该AVPacket所属的视频/音频流。
audio_pkt.data = in;
audio_pkt.size = size;
audio_pkt.pts = time;
audio_pkt.dts = time;
//audio_pkt.pos = -1;
audio_pkt.flags = ;
//audio_pkt.duration = 10;
int ret = av_interleaved_write_frame(ofmt_ctx, &audio_pkt);
if (ret != ) {
//LOGE("----encodeAudio---ret: %d size:%d ,time:%lld ",
// ret, size, time);
}
return ;
}

  初始化相机:

 - (void) initCamera:(BOOL)type
{
NSError *deviceError;
AVCaptureDeviceInput *inputCameraDevice;
if (type==false)
{
inputCameraDevice = [AVCaptureDeviceInput deviceInputWithDevice:cameraDeviceB error:&deviceError];
}
else
{
inputCameraDevice = [AVCaptureDeviceInput deviceInputWithDevice:cameraDeviceF error:&deviceError];
}
AVCaptureVideoDataOutput *outputVideoDevice = [[AVCaptureVideoDataOutput alloc] init]; NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
NSNumber* val = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val forKey:key];
outputVideoDevice.videoSettings = videoSettings;
[outputVideoDevice setSampleBufferDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, )];
captureSession = [[AVCaptureSession alloc] init];
[captureSession addInput:inputCameraDevice];
[captureSession addOutput:outputVideoDevice];
[captureSession beginConfiguration]; [captureSession setSessionPreset:[NSString stringWithString:AVCaptureSessionPreset352x288]];
connectionVideo = [outputVideoDevice connectionWithMediaType:AVMediaTypeVideo];
#if TARGET_OS_IPHONE
[self setRelativeVideoOrientation]; NSNotificationCenter* notify = [NSNotificationCenter defaultCenter];
[notify addObserver:self
selector:@selector(statusBarOrientationDidChange:)
name:@"StatusBarOrientationDidChange"
object:nil];
#endif [captureSession commitConfiguration];
recordLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];
[recordLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
}

  

  设置音频参数

  

 - (void)setupAudioFormat:(UInt32) inFormatID SampleRate:(int)sampeleRate
{
//重置下
memset(&_recordFormat, , sizeof(_recordFormat));
//设置采样率,这里先获取系统默认的测试下 //TODO:
//采样率的意思是每秒需要采集的帧数
_recordFormat.mSampleRate = sampeleRate;//[[AVAudioSession sharedInstance] sampleRate];
UInt32 size = sizeof(_recordFormat.mSampleRate);
//AudioSessionGetProperty( kAudioSessionProperty_CurrentHardwareSampleRate,
// &size,
// &_recordFormat.mSampleRate);
size = sizeof(_recordFormat.mChannelsPerFrame);
// AudioSessionGetProperty( kAudioSessionProperty_CurrentHardwareInputNumberChannels,
// &size,
// &_recordFormat.mChannelsPerFrame); _recordFormat.mFormatID = inFormatID;
if (inFormatID == kAudioFormatLinearPCM){
//这个屌属性不知道干啥的。,//要看看是不是这里属性设置问题
//结果分析: 8bit为1byte,即为1个通道里1帧需要采集2byte数据,再*通道数,即为所有通道采集的byte数目。
//所以这里结果赋值给每帧需要采集的byte数目,然后这里的packet也等于一帧的数据。 _recordFormat.mFramesPerPacket = ;
_recordFormat.mSampleRate =sampeleRate;// 16000.0;
//每个通道里,一帧采集的bit数目 语音每采样点占用位数
_recordFormat.mBitsPerChannel = ;
_recordFormat.mChannelsPerFrame = ;// 1:单声道;2:立体声
_recordFormat.mFramesPerPacket = ;
_recordFormat.mBytesPerFrame = (_recordFormat.mBitsPerChannel / ) * _recordFormat.mChannelsPerFrame;
_recordFormat.mBytesPerPacket = _recordFormat.mBytesPerFrame * _recordFormat.mFramesPerPacket;
//_recordFormat.mBytesPerPacket = _recordFormat.mBytesPerFrame = (_recordFormat.mBitsPerChannel / 8) * _recordFormat.mChannelsPerFrame;
_recordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
//_recordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
}
}

  开始录音:

 -(void)startRecording
{
UInt32 size;
NSError *error = nil;
//设置audio session的category
BOOL ret = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:&error];//注意,这里选的是AVAudioSessionCategoryPlayAndRecord参数,如果只需要录音,就选择Record就可以了,如果需要录音和播放,则选择PlayAndRecord,这个很重要
if (!ret) {
NSLog(@"设置声音环境失败");
return;
}
//启用audio session
ret = [[AVAudioSession sharedInstance] setActive:YES error:&error];
if (!ret)
{
NSLog(@"启动失败");
return;
}
//初始化音频输入队列
AudioQueueNewInput(&_recordFormat, inputBufferHandler, (__bridge void *)(self), NULL, kCFRunLoopCommonModes, , &_audioQueue);//inputBufferHandler这个是回调函数名
size = sizeof(_recordFormat);
//AudioQueueGetProperty(_audioQueue, kAudioQueueProperty_StreamDescription,
// &_recordFormat, &size);
//计算估算的缓存区大小
//int frames = (int)ceil(kDefaultBufferDurationSeconds * _recordFormat.mSampleRate);//返回大于或者等于指定表达式的最小整数
int bufferByteSize =;// frames * _recordFormat.mBytesPerFrame;//缓冲区大小在这里设置,这个很重要,在这里设置的缓冲区有多大,那么在回调函数的时候得到的inbuffer的大小就是多大。
//bufferByteSize=[self ComputeRecordBufferSize:&_recordFormat sss:kDefaultBufferDurationSeconds];
NSLog(@"缓冲区大小:%d",bufferByteSize);
AudioQueueBufferRef _audioBuffers[];
//创建缓冲器
for (int i = ; i < kNumberAudioQueueBuffers; i++){
AudioQueueAllocateBuffer(_audioQueue, bufferByteSize, &_audioBuffers[i]);
AudioQueueEnqueueBuffer(_audioQueue, _audioBuffers[i], , NULL);//将 _audioBuffers[i]添加到队列中
}
// 开始录音
AudioQueueStart(_audioQueue, NULL); }

  源码地址:http://pan.baidu.com/s/1qXOSznA

基于ffmpeg 直播推流和播放rtmp (IOS源码)的更多相关文章

  1. 最简单的基于FFmpeg的移动端例子:IOS 推流器

    转至:http://blog.csdn.net/leixiaohua1020/article/details/47072519   ================================== ...

  2. 最简单的基于FFmpeg的推流器(以推送RTMP为例)

    ===================================================== 最简单的基于FFmpeg的推流器系列文章列表: <最简单的基于FFmpeg的推流器(以 ...

  3. day122:MoFang:OSSRS流媒体直播服务器&基于APICloud的acLive直播推流模块实现RTMP直播推流

    目录 1.docker安装OSSRS流媒体直播服务器 2.基于APICloud的acLive直播推流模块实现RTMP直播推流 3.直播流管理 1.docker安装OSSRS流媒体直播服务器 1.OSS ...

  4. 最简单的基于FFmpeg的移动端例子:IOS 视频解码器-保存

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  5. 最简单的基于FFmpeg的移动端例子:IOS 视频转码器

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  6. 最简单的基于FFMPEG+SDL的音频播放器 ver2 (采用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  7. 最简单的基于FFMPEG+SDL的音频播放器 ver2 (採用SDL2.0)

    ===================================================== 最简单的基于FFmpeg的音频播放器系列文章列表: <最简单的基于FFMPEG+SDL ...

  8. 一个功能齐全的IOS音乐播放器应用源码

    该源码是在ios教程网拿过来的,一个不错的IOS音乐播放器应用源码,这个是我当时进公司时 我用了一晚上写的  图片都是在别的地方扒的,主要是歌词同步,及上一曲,下一曲,功能齐全了 ,大家可以学习一下吧 ...

  9. ios源码-ios游戏源码-ios源码下载

    游戏源码   一款休闲类的音乐小游戏源码 该源码实现了一款休闲类的音乐小游戏源码,该游戏的源码很简单,而且游戏的玩法也很容易学会,只要我们点击视图中的grid,就可以 人气:2943运行环境:/Xco ...

随机推荐

  1. yum安装 lnmp (linux+nginx+php7.1+mysql5.7)

    1.第一步先更新yum update 2.yum安装nginx安装nginx最新源:yum localinstall http://nginx.org/packages/centos/7/noarch ...

  2. 3dsMAX 插件

    SDK C++ 对性能有要求 底层接口 MAXScript 上层接口 a few more function whick sdk does not afford MCG像蓝图一样的东西 http:// ...

  3. How to make an executable jar file?

    https://stackoverflow.com/questions/5258159/how-to-make-an-executable-jar-file 文件的路径如下: package com. ...

  4. WPF一段代码搞定所有的点击事件

    用一个方法来控制转发所有的点击事件,界面图如下:    <Page x:Class="WPFNavigate.Index" xmlns="http://schema ...

  5. JMS之——ActiveMQ 高可用与负载均衡集群安装、配置(ZooKeeper + LevelDB + Static discovery)

    一.说明 从 ActiveMQ 5.9 开始, ActiveMQ 的集群实现方式取消了传统的 Master-Slave 方式,增加了基于ZooKeeper + LevelDB 的 Master-Sla ...

  6. maven 编码GBK的不可映射字符 或者 UTF-8

    要通过修改pom.xml文件,告诉maven这个项目使用UTF-8来编译. 方案一: 在pom.xml的/project/build/plugins/下的编译插件声明中加入下面的配置:<enco ...

  7. LVS-负载均衡

    LVS: LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统.本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一.章 ...

  8. redis3.0.6安装配置

    运行linux客户端 1     安装依赖 yum install gcc-c++ -y(安装gcc) 2     创建安装目录.编译.安装 mkdir -p /usr/local/redis(创建安 ...

  9. PHP多文件上传代码练习

    HTML表单: <html> <head><title>upload file</title> <meta http-equiv="Co ...

  10. HDU 1253 胜利大逃亡 NYOJ 523【BFS】

    胜利大逃亡 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...