• 基于ffmpeg 直播推流和播放rtmp (IOS源码)


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

      

      ffmpeg初始化代码如下:

     1 int init_Code(int width, int height, const char *out_path) {
     2     av_log_set_callback(custom_log);
     3     //avcodec_register_all();
     4     av_register_all();
     5     avformat_network_init();
     6     avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", out_path);
     7     
     8     //Open output URL,set before avformat_write_header() for muxing
     9     AVOutputFormat * ofmt = ofmt_ctx->oformat;
    10     if (!(ofmt->flags & AVFMT_NOFILE)) { //Open output URL
    11         if (avio_open(&ofmt_ctx->pb, out_path, AVIO_FLAG_READ_WRITE) < 0) {
    12             return -1;
    13         }
    14     }
    15     if (isAudio == 1) {
    16         if (init_audio_Code() != 0)//初始化 音频参数
    17             return -1;
    18     }
    19     if (isVideo == 1) {
    20         if (init_video_code(width, height) != 0)//初始化 视频参数
    21             return -1;
    22     }
    23     av_dump_format(ofmt_ctx, 0, out_path, 1);
    24     if (avformat_write_header(ofmt_ctx, NULL) < 0) { //Write file header
    25         //LOGE("Error occurred when opening output file
    ");
    26         return -1;
    27     }
    28     
    29     start_thread_encode(); //开始编码
    30     return 0;
    31 }

       

      视频硬编码:

     1 /* 视频 硬编码**/
     2 int encodeVideo_h264(uint8_t* in, int64_t time, int size, int keyframe) {
     3     int ret;
     4     // 定义AVPacket对象后,请使用av_init_packet进行初始化
     5     av_init_packet(&video_pkt);
     6     //av_new_packet(&video_pkt,size);
     7     video_pkt.stream_index = video_st->index;
     8     video_pkt.data = in;
     9     
    10     video_pkt.size = size;
    11     video_pkt.pos = -1;
    12     ptsPacket(video_st, &video_pkt, time);
    13     if (video_pkt.buf != NULL) {
    14         video_pkt.buf->data = in;
    15         video_pkt.buf->size = size;
    16     }
    17     video_pkt.flags = keyframe;
    18     if (keyframe == 1) {
    19         //LOGE("硬编码-关键帧: %lld", time);
    20     }
    21     
    22     ret = av_interleaved_write_frame(ofmt_ctx, &video_pkt);
    23     if (ret != 0) {
    24         printf("----encodeVideo--encodeVideo  -ret: %d ", ret);
    25         //LOGE("----encodeVideo--encodeVideo  -ret: %d ", ret);
    26     }
    27     av_free_packet(&video_pkt);
    28 
    29     return 0;
    30 }

      音频硬编码:

     1 /* 音频 硬编码**/
     2 int encodeAudio_AAC(uint8_t* in, int64_t time, int size) {
     3     if (isAudio == 0)
     4         return 0;
     5     av_init_packet(&audio_pkt);
     6     int got_frame = 0;
     7     audio_pkt.stream_index = audio_st->index; //标识该AVPacket所属的视频/音频流。
     8     audio_pkt.data = in;
     9     audio_pkt.size = size;
    10     audio_pkt.pts = time;
    11     audio_pkt.dts = time;
    12     //audio_pkt.pos = -1;
    13     audio_pkt.flags = 1;
    14     //audio_pkt.duration = 10;
    15     int ret = av_interleaved_write_frame(ofmt_ctx, &audio_pkt);
    16     if (ret != 0) {
    17         //LOGE("----encodeAudio---ret: %d  size:%d  ,time:%lld ",
    18         //      ret, size, time);
    19     }
    20     return 0;
    21 }

      初始化相机:

     1 - (void) initCamera:(BOOL)type
     2 {
     3     NSError *deviceError;
     4     AVCaptureDeviceInput *inputCameraDevice;
     5     if (type==false)
     6     {
     7         inputCameraDevice = [AVCaptureDeviceInput deviceInputWithDevice:cameraDeviceB error:&deviceError];
     8     }
     9     else
    10     {
    11         inputCameraDevice = [AVCaptureDeviceInput deviceInputWithDevice:cameraDeviceF error:&deviceError];
    12     }
    13     AVCaptureVideoDataOutput *outputVideoDevice = [[AVCaptureVideoDataOutput alloc] init];
    14     
    15     NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
    16     NSNumber* val = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange];
    17     NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:val forKey:key];
    18     outputVideoDevice.videoSettings = videoSettings;
    19     [outputVideoDevice setSampleBufferDelegate:self queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)];
    20     captureSession = [[AVCaptureSession alloc] init];
    21     [captureSession addInput:inputCameraDevice];
    22     [captureSession addOutput:outputVideoDevice];
    23     [captureSession beginConfiguration];
    24     
    25     [captureSession setSessionPreset:[NSString stringWithString:AVCaptureSessionPreset352x288]];
    26     connectionVideo = [outputVideoDevice connectionWithMediaType:AVMediaTypeVideo];
    27 #if TARGET_OS_IPHONE
    28     [self setRelativeVideoOrientation];
    29     
    30     NSNotificationCenter* notify = [NSNotificationCenter defaultCenter];
    31     [notify addObserver:self
    32                selector:@selector(statusBarOrientationDidChange:)
    33                    name:@"StatusBarOrientationDidChange"
    34                  object:nil];
    35 #endif
    36     
    37     [captureSession commitConfiguration];
    38     recordLayer = [AVCaptureVideoPreviewLayer    layerWithSession:captureSession];
    39     [recordLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
    40 }

      

      设置音频参数

      

     1 - (void)setupAudioFormat:(UInt32) inFormatID SampleRate:(int)sampeleRate
     2 {
     3     //重置下
     4     memset(&_recordFormat, 0, sizeof(_recordFormat));
     5     //设置采样率,这里先获取系统默认的测试下 //TODO:
     6     //采样率的意思是每秒需要采集的帧数
     7     _recordFormat.mSampleRate = sampeleRate;//[[AVAudioSession sharedInstance] sampleRate];
     8     UInt32 size = sizeof(_recordFormat.mSampleRate);
     9     //AudioSessionGetProperty(    kAudioSessionProperty_CurrentHardwareSampleRate,
    10     //                                    &size,
    11     //                                  &_recordFormat.mSampleRate);
    12     size = sizeof(_recordFormat.mChannelsPerFrame);
    13     // AudioSessionGetProperty(    kAudioSessionProperty_CurrentHardwareInputNumberChannels,
    14     //                                      &size,
    15     //                                    &_recordFormat.mChannelsPerFrame);
    16 
    17     _recordFormat.mFormatID = inFormatID;
    18     if (inFormatID == kAudioFormatLinearPCM){
    19         //这个屌属性不知道干啥的。,//要看看是不是这里属性设置问题
    20         //结果分析: 8bit为1byte,即为1个通道里1帧需要采集2byte数据,再*通道数,即为所有通道采集的byte数目。
    21         //所以这里结果赋值给每帧需要采集的byte数目,然后这里的packet也等于一帧的数据。
    22 
    23         _recordFormat.mFramesPerPacket = 1;
    24         _recordFormat.mSampleRate =sampeleRate;// 16000.0;
    25         //每个通道里,一帧采集的bit数目 语音每采样点占用位数
    26         _recordFormat.mBitsPerChannel = 16;
    27         _recordFormat.mChannelsPerFrame = 2;// 1:单声道;2:立体声
    28         _recordFormat.mFramesPerPacket = 1;
    29         _recordFormat.mBytesPerFrame = (_recordFormat.mBitsPerChannel / 8) * _recordFormat.mChannelsPerFrame;
    30         _recordFormat.mBytesPerPacket = _recordFormat.mBytesPerFrame * _recordFormat.mFramesPerPacket;
    31         //_recordFormat.mBytesPerPacket = _recordFormat.mBytesPerFrame = (_recordFormat.mBitsPerChannel / 8) * _recordFormat.mChannelsPerFrame;
    32         _recordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    33         //_recordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    34     }
    35 }

      开始录音:

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

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

  • 相关阅读:
    Replay_InsertTrigger
    什么是内网IP地址,常用的内网IP地址段有哪些?
    Repeater嵌套绑定Repeater
    window.history.go(1)和window.location.go(1)的区别
    如何对SQL Server中的tempdb“减肥”
    IIS Temporary ASP.NET Files拒绝访问解决方案
    Server Application Unavailable出现的原因及解决方案集锦
    Sqlserver查找非数字数据行
    C++中的指针,指针函数和函数指针
    char * p = "abc"与const char *p = "abc"
  • 原文地址:https://www.cnblogs.com/netuml/p/6557030.html
Copyright © 2020-2023  润新知