2013-02-03 99 views
4

我將視頻逐幀轉碼並使用x264 + ffmpeg進行編碼。原始視頻播放良好,但我的轉碼視頻的前幾幀顯示灰色文物。我知道這是因爲時間壓縮和幾幀後這些文物消失。視頻編碼和關鍵幀

看到這兩張照片是第一幀和第二幀。第三架是正常的(即沒有灰色的人工製品,而不是模糊的像第二個) First frame Second frame

我怎樣才能迫使第一幀是一個關鍵幀(即完全在我的輸出視頻編碼),使這些文物不顯示?

編輯 - 更多詳情

下面是我在做什麼更詳細。我使用位形式的不同教程來逐幀讀取視頻,並將每幀重新編碼爲新視頻。我的編碼參數如下:

avcodec_get_context_defaults3(c, *codec); 
c->codec_id = codec_id; 
c->bit_rate = output_bitrate; 
/* Resolution must be a multiple of two. */ 
c->width = output_width; 
c->height = output_height; 
/* 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. */ 
st->r_frame_rate.num = output_framerate_num; 
st->r_frame_rate.den = output_framerate_den; 
c->time_base.den = output_timebase_den; 
c->time_base.num = output_timebase_num; 
c->gop_size  = 3; /* emit one intra frame every twelve frames at most */ 
c->pix_fmt  = STREAM_PIX_FMT; 
if (c->codec_id == AV_CODEC_ID_MPEG2VIDEO) { 
    /* just for testing, we also add B frames */ 
    c->max_b_frames = 2; 
} 
if (c->codec_id == AV_CODEC_ID_MPEG1VIDEO) { 
    /* Needed to avoid using macroblocks in which some coeffs overflow. 
    * This does not happen with normal video, it just happens here as 
    * the motion of the chroma plane does not match the luma plane. */ 
    c->mb_decision = 2; 
} 
c->max_b_frames = 2; 
c->scenechange_threshold = 0; 
c->rc_buffer_size = 0; 
c->me_method = ME_ZERO; 

然後我處理每一幀,可能做錯了。解碼位:

while(av_read_frame(gFormatCtx, &packet)>=0) { 
    // Is this a packet from the video stream? 
    if(packet.stream_index==gVideoStreamIndex) { 
     // Decode video frame 
     avcodec_decode_video2(gVideoCodecCtx, pCurrentFrame, &frameFinished, &packet); 
     // Did we get a video frame? 
     if(frameFinished) { 
      [...] 
      if(firstPts == -999) /*Initial value*/ 
       firstPts = packet.pts; 
      deltaPts = packet.pts - firstPts; 
      double seconds = deltaPts*av_q2d(gFormatCtx->streams[gVideoStreamIndex]->time_base); 
      [...] 
      muxing_writeVideoFrame(pCurrentFrame, packet.pts); 
     } 
    } 
} 

實際寫作:

int muxing_writeVideoFrame(AVFrame *frame, int64_t pts) 
{ 
frameCount = frameCount +1; 
if(frameCount > 0) 
{ 
    if (video_st) 
     video_pts = (double)video_st->pts.val * video_st->time_base.num/
        video_st->time_base.den; 
    else 
     video_pts = 0.0; 

    if (video_st && !(video_st && audio_st && audio_pts < video_pts)) 
    { 
     frame->pts = pts;//av_rescale_q(frame_count, video_st->codec->time_base, video_st->time_base); 
     write_video_frame(oc, video_st, frame); 
    } 
} 

return 0; 
} 

static int write_video_frame(AVFormatContext *oc, AVStream *st, AVFrame *frame) 
{ 
    int ret; 
    static struct SwsContext *sws_ctx; 
    //LOGI(10, frame_count); 
    AVCodecContext *c = st->codec; 

    /* encode the image */ 
    AVPacket pkt; 
    int got_output; 
    av_init_packet(&pkt); 
    pkt.data = NULL; // packet data will be allocated by the encoder 
    pkt.size = 0; 
ret = avcodec_encode_video2(c, &pkt, frame, &got_output); 
if (ret < 0) { 
    fprintf(stderr, "Error encoding video frame: %s\n", av_err2str(ret)); 
    exit(1); 
} 
/* If size is zero, it means the image was buffered. */ 
if (got_output) { 
    if (c->coded_frame->key_frame) 
     pkt.flags |= AV_PKT_FLAG_KEY; 
    pkt.stream_index = st->index; 
    /* Write the compressed frame to the media file. */ 
    ret = av_interleaved_write_frame(oc, &pkt); 
} else { 
    ret = 0; 
} 

    if (ret != 0) { 
     LOGI(10, av_err2str(ret)); 
     exit(1); 
    } 
    frame_count++; 
    return got_output; 
} 
+0

除非你顯示ffmpeg命令和完整的控制檯輸出,那麼我們只能猜測。 – LordNeckbeard

回答

1

這是因爲你的視頻不具有 keyframe開始。爲了解決這個問題,我使用AviDemux。與2.6版

  • MP4複用器
  • MP4v2複用器

,並沒有開始一個關鍵幀可能更支持視頻開始。

1

你的問題很可能在解碼部分不是編碼(x264不能產生這樣的文物)。正如上面所說,它看起來像你不是從關鍵幀開始解碼(或者可能是你的流是開放式的,而你沒有放棄第一個B幀)。

+1

爲了證實這一點,我嘗試丟棄我解碼的前10幀 - 這比我在轉碼視頻上得到的損壞幀的數量要多得多。這給出完全相同的結果。我也嘗試在屏幕上顯示所有解碼的幀,並且它們看起來不錯。它在編碼方面必然是錯誤的。 – tishu

+0

上傳小編碼樣本。但我仍然認爲它是解碼問題,或者您錯誤地使用了x264 API(將它發送到代碼轉換鏈中間的某處)。 – nobody555

+0

感謝您的回覆。我已經發布了一個[示例原始文件](http://dl.free.fr/jazSYmaGF)(在紅色框中選擇「Valider et telecharger le fichier」)以及由此產生的[轉碼文件](http:// dl。 free.fr/vf0MF8LZ5)顯示工件。 – tishu