2013-07-17 96 views
3

通过一点挖掘,我发现了一个库,它在写入时从.mp4文件中提取NAL单元。我正尝试使用libavformatlibavcodec将此信息打包到flv上。我设置使用的视频流:iOS上的RTMP上的H264视频流

-(void)setupVideoStream { 
    int ret = 0; 
    videoCodec = avcodec_find_decoder(STREAM_VIDEO_CODEC); 

    if (videoCodec == nil) { 
     NSLog(@"Could not find encoder %i", STREAM_VIDEO_CODEC); 
     return; 
    } 

    videoStream         = avformat_new_stream(oc, videoCodec); 

    videoCodecContext       = videoStream->codec; 

    videoCodecContext->codec_type    = AVMEDIA_TYPE_VIDEO; 
    videoCodecContext->codec_id     = STREAM_VIDEO_CODEC; 
    videoCodecContext->pix_fmt     = AV_PIX_FMT_YUV420P; 
    videoCodecContext->profile     = FF_PROFILE_H264_BASELINE; 

    videoCodecContext->bit_rate     = 512000; 
    videoCodecContext->bit_rate_tolerance  = 0; 

    videoCodecContext->width     = STREAM_WIDTH; 
    videoCodecContext->height     = STREAM_HEIGHT; 

    videoCodecContext->time_base.den   = STREAM_TIME_BASE; 
    videoCodecContext->time_base.num   = 1; 
    videoCodecContext->gop_size     = STREAM_GOP; 

    videoCodecContext->has_b_frames    = 0; 
    videoCodecContext->ticks_per_frame   = 2; 

    videoCodecContext->qcompress    = 0.6; 
    videoCodecContext->qmax      = 51; 
    videoCodecContext->qmin      = 10; 
    videoCodecContext->max_qdiff    = 4; 
    videoCodecContext->i_quant_factor   = 0.71; 

    if (oc->oformat->flags & AVFMT_GLOBALHEADER) 
     videoCodecContext->flags    |= CODEC_FLAG_GLOBAL_HEADER; 

    videoCodecContext->extradata    = avcCHeader; 
    videoCodecContext->extradata_size   = avcCHeaderSize; 

    ret = avcodec_open2(videoStream->codec, videoCodec, NULL); 
    if (ret < 0) 
     NSLog(@"Could not open codec!"); 
} 

然后我连接,并且每个文库中提取NALU时,它返回一个数组保持一个或两个的NALU到我RTMPClient。该处理实际流的方法是这样的:

-(void)writeNALUToStream:(NSArray*)data time:(double)pts { 
    int ret = 0; 
    uint8_t *buffer = NULL; 
    int bufferSize = 0; 

    // Number of NALUs within the data array 
    int numNALUs = [data count]; 

    // First NALU 
    NSData *fNALU = [data objectAtIndex:0]; 
    int fLen = [fNALU length]; 

    // If there is more than one NALU... 
    if (numNALUs > 1) { 
     // Second NALU 
     NSData *sNALU = [data objectAtIndex:1]; 
     int sLen = [sNALU length]; 

     // Allocate a buffer the size of first data and second data 
     buffer = av_malloc(fLen + sLen); 

     // Copy the first data bytes of fLen into the buffer 
     memcpy(buffer, [fNALU bytes], fLen); 

     // Copy the second data bytes of sLen into the buffer + fLen + 1 
     memcpy(buffer + fLen + 1, [sNALU bytes], sLen); 

     // Update the size of the buffer 
     bufferSize = fLen + sLen; 
    }else { 
     // Allocate a buffer the size of first data 
     buffer = av_malloc(fLen); 

     // Copy the first data bytes of fLen into the buffer 
     memcpy(buffer, [fNALU bytes], fLen); 

     // Update the size of the buffer 
     bufferSize = fLen; 
    } 

    // Initialize the packet 
    av_init_packet(&pkt); 

    //av_packet_from_data(&pkt, buffer, bufferSize); 

    // Set the packet data to the buffer 
    pkt.data   = buffer; 
    pkt.size   = bufferSize; 
    pkt.pts    = pts; 

    // Stream index 0 is the video stream 
    pkt.stream_index = 0; 

    // Add a key frame flag every 15 frames 
    if ((processedFrames % 15) == 0) 
     pkt.flags  |= AV_PKT_FLAG_KEY; 

    // Write the frame to the stream 
    ret = av_interleaved_write_frame(oc, &pkt); 
    if (ret < 0) 
     NSLog(@"Error writing frame %i to stream", processedFrames); 
    else { 
     // Update the number of frames successfully streamed 
     frameCount++; 
     // Update the number of bytes successfully sent 
     bytesSent += pkt.size; 
    } 

    // Update the number of frames processed 
    processedFrames++; 
    // Update the number of bytes processed 
    processedBytes += pkt.size; 

    free((uint8_t*)buffer); 
    // Free the packet 
    av_free_packet(&pkt); 
} 

之后大约100左右的帧,我得到一个错误: malloc: *** error for object 0xe5bfa0: incorrect checksum for freed object - object was probably modified after being freed. *** set a breakpoint in malloc_error_break to debug

似乎我不能以阻止发生。我试过注释av_free_packet()方法和free()以及尝试使用av_packet_from_data(),而不是初始化数据包并设置数据和大小值。

我的问题是;我怎么能阻止这个错误发生,根据wireshark,这些都是正确的RTMP h264数据包,但它们不会播放比黑屏更多的东西。我忽略了一些明显的错误吗?

+0

您是否找到了解决方案?我试图达到同样的目的。当我尝试播放视频时,我会看到一些绿框。你用什么库来阅读NALU?谢谢。 –

回答

1

它看起来像你对我溢满您的缓冲区,并破坏你在这里流:

memcpy(buffer + fLen + 1, [sNALU bytes], sLen); 

您分配FLEN + SLEN字节,然后写fLen + sLen + 1字节。只需摆脱+ 1.

因为您的AVPacket分配在堆栈av_free_packet()是不需要的。 最后,为libav分配额外的字节被认为是很好的做法。 av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE)

+0

您是否找到了解决方案?我试图达到同样的目的。当我尝试播放视频时,我会看到一些绿框。你用什么库来阅读NALU?谢谢。 –