iOS 平台使用 ffmpeg 保存相机数据为MP4,视频非常卡
PHP中文网
PHP中文网 2017-04-18 09:52:00
0
0
492

ios 使用 ffmpeg 将硬编码之后的音视频数据保存为mp4, 结果音频播放正常,视频非常的卡,音频播放完的时候,视频还有3/4没有播完,好几秒跳一帧。时间戳打印了一下,发现没有问题,下面在计算pts的时候好像有问题,但不知道该怎么处理,pkt.pts = av_rescale_q(num_frame, vSt->codec->time_base, vSt->time_base);这一行代码 若将 num_frame /5 之后这视频播放挺流畅,但音视频还是有少许的错位。
保存MP4用的是 ffmpeg 中的av_interleaved_write_frame 等接口,具体代码在下面:

// 写视频数据
void h264_record::write_frame( const void* p, int len, uint32_t timestamp  )
{
    // printf("tttttttttttttttttt: %lld\n", timestamp);
    CriticalSectionScoped lock(_recordVoipCrit);

    if (!formatCtxt_ || videoStreamdIndex_ < 0 )
        return;
    
    AVStream *vSt = formatCtxt_->streams[videoStreamdIndex_];
    AVStream *pst = formatCtxt_->streams[ audioStreamdIndex_ ];
    // Init packet
    AVPacket pkt;
    av_init_packet( &pkt );
    pkt.flags |= ( 0 == getVopType( p, len ) ) ? AV_PKT_FLAG_KEY : 0;   
    pkt.stream_index = vSt->index;
    pkt.data = (uint8_t*)p;
    pkt.size = len;

    // Wait for key frame
    if ( waitkey_ ) {
        if ( 0 == ( pkt.flags & AV_PKT_FLAG_KEY ) )
            return;
        else
            waitkey_ = 0;
    }

    pkt.dts = AV_NOPTS_VALUE;
    pkt.pts = AV_NOPTS_VALUE;

    if(baseH264TimeStamp_ == 0) {
        baseH264TimeStamp_ = timestamp;
    }
    
    AVCodecContext *avccxt = vSt->codec;

    float seconds = (float)(timestamp - baseH264TimeStamp_)/90000;
    if (seconds < 0) {
        WEBRTC_TRACE(cloopenwebrtc::kTraceError,
            cloopenwebrtc::kTraceVideoCoding,
            0,
            "timestamp:%d baseH264TimeStamp_:%d seconds:%f\n",
            timestamp, baseH264TimeStamp_, seconds);
        return;
    }
    // 1/fps
    float timebase = (float)avccxt->time_base.num/avccxt->time_base.den;

    //算出这是第几帧, 不知道这个地方有没有问题
    uint32_t num_frame = (uint32_t)(seconds / timebase);
    if(num_frame !=0 && (num_frame <= lastVideoFrameNum_)) {
        num_frame = lastVideoFrameNum_ + 1;
    }
  
    pkt.pts = av_rescale_q(num_frame, vSt->codec->time_base, vSt->time_base);
    lastVideoFrameNum_ = num_frame;
    int ret = av_interleaved_write_frame(formatCtxt_, &pkt);
    if(ret != 0) {

    }
}

VideoStream 创建设置:

static AVStream* add_video_stream(AVFormatContext *oc,  enum AVCodecID codec_id, unsigned char *data)
{
    
    AVStream *formatSt = avformat_new_stream(oc, NULL);
    if (!formatSt) {
        WEBRTC_TRACE(cloopenwebrtc::kTraceError,
            cloopenwebrtc::kTraceVideoCoding,
            0,
            "Could not allocate stream\n");
        return NULL;
    }

    formatSt->id = 0;//oc->nb_streams-1;

    AVCodec codec= {0};
    codec.type= AVMEDIA_TYPE_VIDEO;

    AVCodecContext *context = formatSt->codec;
    avcodec_get_context_defaults3( context, &codec );
 
    context->codec_type = AVMEDIA_TYPE_VIDEO;
    context->codec_id = AV_CODEC_ID_H264;
    context->pix_fmt = AV_PIX_FMT_YUV420P;

    formatSt->time_base.num = 1;
    formatSt->time_base.den = 90000;

    context->time_base.num = 1;
    context->time_base.den = 15;

    context->extradata = (unsigned char*)malloc(34);
    memcpy(context->extradata, data, 34); //pps sps data
    context->extradata_size = 34;
    //c->bits_per_coded_sample = 0;

    SequenceParameterSet spsSet;
    memset(&spsSet, 0, sizeof(SequenceParameterSet));
    spsSet.Parse(context->extradata+4, 34);
    //c->bit_rate = 0;
    context->width = (spsSet.pic_width_in_mbs_minus1+1)*16;
    context->height = (spsSet.pic_height_in_map_units_minus1 +1)*16;

    ///* Some formats want stream headers to be separate. */
    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
        context->flags |= CODEC_FLAG_GLOBAL_HEADER;

    return formatSt;
}

这是我第一次使用ffmpeg ,代码的流程基本知道怎么回事了。问题在网上找了一周多了,github上相关的代码也搜了,实在找不到什么问题,希望大家会的能帮帮忙,谢谢!

PHP中文网
PHP中文网

认证0级讲师

全員に返信(0)
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート