2013-02-03 2 views
4

Je transcodage une vidéo image par image et utilise x264 + ffmpeg pour coder. La vidéo originale fonctionne bien, mais les premières images de mon vidéodisque transcodé montrent des artefacts gris. Je comprends que c'est à cause de la compression temporelle et que ces artefacts disparaissent après quelques images.Codage vidéo et images-clés

Voir ces deux images qui sont les première et deuxième images. Le troisième cadre est normal (pas d'artefact gris et non floue comme la seconde) First frame Second frame

Comment puis-je forcer la première image à une image clé (ie entièrement codée dans ma vidéo de sortie) afin que ceux-ci les artefacts ne montrent pas?

Edition - plus de détails

Voici ce que je fais plus de détails. J'ai utilisé des tutoriels différents pour lire une vidéo image par image et réencoder chaque image dans une nouvelle vidéo. Mes paramètres de codage sont les suivants:

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; 

Ensuite, je traite chaque image, probablement en y faisant quelque chose de mal. Le bit de décodage:

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); 
     } 
    } 
} 

L'écriture réelle:

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

À moins d'afficher la commande ffmpeg et la sortie de console complète, nous ne pouvons que deviner. – LordNeckbeard

Répondre

1

Ceci est parce que votre vidéo ne démarre pas avec un keyframe. Pour résoudre ce problème, j'utilise AviDemux. A partir de la version 2,6

  • MP4 Muxer
  • MP4v2 Muxer

et peut-être plus de vidéo de soutien à partir sans images clés.

1

Votre problème est le plus susceptible de décoder une partie non codée (x264 ne peut pas produire de tels artefacts). Et comme il a été dit plus haut, il semblerait que vous commenciez à décoder non pas à partir d'une image clé (ou que votre flux soit open-gop et que vous n'ayez pas ignoré les premières images B).

+1

Pour confirmer cela, j'ai essayé de supprimer les 10 premières images que je décode - ce qui est beaucoup plus que le nombre d'images corrompues que je reçois sur ma vidéo transcodée. Cela donne exactement le même résultat. J'ai également essayé d'afficher tous les cadres décodés sur l'écran et ils ont l'air bien. Ce doit être quelque chose de mal du côté de l'encodage. – tishu

+0

Téléchargez un petit échantillon codé quelque part. Mais je pense toujours qu'il s'agit d'un problème de décodage ou que vous utilisez incorrectement l'API x264 (envoyez-le dans un cadre au milieu de votre chaîne de transcodage). – nobody555

+0

Merci pour votre réponse. J'ai posté un [exemple de fichier original] (http://dl.free.fr/jazSYmaGF) (sélectionnez "Valider et telecharger le fichier" dans la case rouge) et le résultat [fichier transcodé] (http: // dl. free.fr/vf0MF8LZ5) qui montre les artefacts. – tishu