ffmpeg+sdl播放视频过快

时间:2022-07-21 12:04:32
   AVFormatContext *pFormatCtx; 
    int i, videoStream(-1); 
    AVCodecContext *pCodecCtx; 
    AVCodec *pCodec; 
    AVFrame *pFrame; 
    AVPacket packet; 
    int frameFinished; 
    float aspect_ratio; 
    AVCodecContext *aCodecCtx; 
    SDL_Overlay *bmp; 
    SDL_Surface *screen; 
    SDL_Rect rect; 
    SDL_Event event; 
  
//初始化SDL
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) 

fprintf(stderr, "Could not initialize SDL - %s/n" , SDL_GetError()); 
exit(1); 



    av_register_all(); 
                 const char * filename = "D:\\Wildlife.wmv";
          //申请一段内存
/* hwndDisplay= GetDlgItem(IDC_STATIC_PICTRUE)->GetSafeHwnd();
 GetDlgItem(IDC_STATIC_PICTRUE)->GetClientRect(rcDisplay);
 char szVar[MAX_PATH];
 sprintf(szVar,"SDL_WINDOWID=0x%lx" ,hwndDisplay);
 SDL_putenv(szVar);*/
    pFormatCtx = avformat_alloc_context(); 
    if (!pFormatCtx)
                { 
        fprintf(stderr, "Memory error/n"); 
        exit(1); 
    } 
             //参数ypFormatCtx包含一切媒体相关的上下文结构,有它就有了一切,本函数如果打开媒体成功|,
                 //会返回一个AVFormatContext的实例.
                 //参数yfilename是媒体文件名或URL.
                 //打开视频文件
    if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0) 
        return;//打开失败
 // 检查文件中的流信息
    if(av_find_stream_info(pFormatCtx)<0) 
        return ;
    // Dump information about file onto standard error 
     
 
    // Find the first video stream 
  //pFormatCtx->streams是一组大小为apFormatCtx->nb_streams的指针
                 //接着我们寻找一个视频流
    for(i=0; i<pFormatCtx->nb_streams; i++) 
    { 
        if(pFormatCtx->streams[i]->codec->codec_type== AVMEDIA_TYPE_VIDEO&& videoStream<0) 
        { 
            videoStream=i; 
        } 
    } 
 
    if(videoStream==-1) 
      return ; // Didn't find a video stream 
 
    // Get a pointer to the codec context for the video stream 
  //流中关于编解码器的信息我们叫做code context,包含了所使用的编解码器信息,这里我们得到了指向他的指针
    pCodecCtx=pFormatCtx->streams[videoStream]->codec; 
   //接下来寻找真的编解码器,并且打开他
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id); 
    if(pCodec==NULL) 
    { 
        fprintf(stderr, "Unsupported codec!/n"); 
        return ; // Codec not found 
    } 
    // Open codec 
    if(avcodec_open(pCodecCtx, pCodec)<0) 
        return ; // Could not open codec 
 
    // Allocate video frame 
    pFrame=avcodec_alloc_frame(); 
 
    uint8_t *buffer; 
    int numBytes; 
    // Determine required buffer size and allocate buffer 

    numBytes=avpicture_get_size(PIX_FMT_RGB24, pCodecCtx->width, 
        pCodecCtx->height); 
    buffer=(uint8_t *)av_malloc(numBytes* sizeof(uint8_t)); 


#ifndef __DARWIN__ 
    screen = SDL_SetVideoMode(rcDisplay.Width(), rcDisplay.Height(), 0, 0); 
#else 
    screen = SDL_SetVideoMode(rcDisplay.Width(), rcDisplay.Height(), 24, 0); 
#endif 
    if(!screen) 
    { 
        fprintf(stderr, "SDL: could not set video mode - exiting/n" ); 
        exit(1); 
    } 

 //创建绘制YUV数据的句柄  
    bmp = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, 
        SDL_YV12_OVERLAY, screen); 
 
    static struct SwsContext *img_convert_ctx; 
    if (img_convert_ctx == NULL) 
    { 
//图像格式转化,返回上下文句柄
        img_convert_ctx = sws_getContext(rcDisplay.Width(), rcDisplay.Height(), 
                                         pCodecCtx->pix_fmt, 
                                        pCodecCtx->width, pCodecCtx->height, 
                                         PIX_FMT_YUV420P, 
                                         sws_flags, NULL, NULL, NULL); 
        if (img_convert_ctx == NULL) 
        { 
            fprintf(stderr, "Cannot initialize the conversion context/n" ); 
            exit(1); 
        } 
    } 
    i=0; 
//不停的从码流中提取帧数据
    while(av_read_frame(pFormatCtx, &packet)>=0) 
    { 
        // Is this a packet from the video stream? 
        if(packet.stream_index==videoStream) 
        { 
            // Decode video frame 

            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, 
                &packet); 
            // Did we get a video frame? 
            if(frameFinished) 
            { 
                // Convert the image from its native format to RGB 
                /*sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,
                      0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);*/  
                // Save the frame to disk 
                /*if(++i<=5)
                    SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);*/  
///锁定一个覆盖,以便于在屏幕上显示
                SDL_LockYUVOverlay(bmp); 
                AVPicture pict; 
                pict.data[0] = bmp->pixels[0]; 
                pict.data[1] = bmp->pixels[2]; 
                pict.data[2] = bmp->pixels[1]; 
 
                pict.linesize[0] = bmp->pitches[0]; 
                pict.linesize[1] = bmp->pitches[2]; 
                pict.linesize[2] = bmp->pitches[1]; 
 
                // Convert the image into YUV format that SDL uses 
                /*img_convert(&pict, PIX_FMT_YUV420P,
                    (AVPicture *)pFrame, pCodecCtx->pix_fmt,
                    pCodecCtx->width, pCodecCtx->height);*/ 

                sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize, 
                    0,pCodecCtx->height, pict.data, pict.linesize); 
//解锁先前锁定的覆盖
                SDL_UnlockYUVOverlay(bmp); 
                rect.x = 0; 
                rect.y = 0; 
                rect.w = rcDisplay.Width(); 
                rect.h = rcDisplay.Height(); 
                SDL_DisplayYUVOverlay(bmp, &rect); 

                
            } 
        } 
 
        // Free the packet that was allocated by av_read_frame 
        av_free_packet(&packet); 
 
        SDL_PollEvent(& event); 
        switch(event .type) 
        { 
        case SDL_QUIT: 
            SDL_Quit(); 
            exit(0); 
            break; 
        default: break ; 
        } 
    } 
    // Free the YUV image 
    av_free(buffer); 
    //av_free(pFrameRGB); 
    // Free the YUV frame 
    av_free(pFrame); 
    // Close the codec 
    avcodec_close(pCodecCtx); 
    // Close the video file 
    av_close_input_file(pFormatCtx); 
 
return ;

9 个解决方案

#1


你要根据PTS DTS做音视频同步

#2


http://blog.csdn.net/mu399/article/details/5814901

#3


没怎么看代码,太长!
视频播放太快的话,是不是帧率太大引起的,调低点试试

#4


你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确

#5


引用 3 楼 max_min_ 的回复:
没怎么看代码,太长!
视频播放太快的话,是不是帧率太大引起的,调低点试试

调低了time_base,还是一样,但是pts和dts我不知道要设置成什么值

#6


引用 4 楼 luoxiang000 的回复:
你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确

用sleep没多大意义啊

#7


用ffmpeg了?那么请参考一下ffmpeg源码里那个ffplay.c吧

#8


最近在做音视频同步 蛋疼的很

#9


要做音视频同步

#1


你要根据PTS DTS做音视频同步

#2


http://blog.csdn.net/mu399/article/details/5814901

#3


没怎么看代码,太长!
视频播放太快的话,是不是帧率太大引起的,调低点试试

#4


你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确

#5


引用 3 楼 max_min_ 的回复:
没怎么看代码,太长!
视频播放太快的话,是不是帧率太大引起的,调低点试试

调低了time_base,还是一样,但是pts和dts我不知道要设置成什么值

#6


引用 4 楼 luoxiang000 的回复:
你是从文件里面读取出来的,一般简单的做一个sleep也是可以的,但是这个不准确

用sleep没多大意义啊

#7


用ffmpeg了?那么请参考一下ffmpeg源码里那个ffplay.c吧

#8


最近在做音视频同步 蛋疼的很

#9


要做音视频同步