FFMPEG+SDL解码出现声音视频都是一卡一卡的

这是一个账号007 2014-12-24 10:08:49
雷同学的源代码参考

音视频分离:http://blog.csdn.net/leixiaohua1020/article/details/39802819
音频播放器:http://blog.csdn.net/leixiaohua1020/article/details/10528443
视频播放器:http://blog.csdn.net/leixiaohua1020/article/details/38868499

现在我是把这几个结合起来了,做一个分离TS流,然后音视频同时解码。


#include <stdio.h>

extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
//新版里的图像转换结构需要引入的头文件
#include "libswscale/swscale.h"
//解码音频抄过来的。
#include "libswresample/swresample.h"
//SDL
#include "sdl/SDL.h"
#include "sdl/SDL_thread.h"

};

//Refresh
#define SFM_REFRESH_EVENT (SDL_USEREVENT + 1)

#define MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio

int thread_exit=0;


static Uint8 *audio_chunk;
static Uint32 audio_len;
static Uint8 *audio_pos;

/* The audio function callback takes the following parameters:
* stream: A pointer to the audio buffer to be filled
* len: The length (in bytes) of the audio buffer
* 回调函数
*/
void fill_audio(void *udata,Uint8 *stream,int len){
if(audio_len==0) /* Only play if we have data left */
return;
len=(len>audio_len?audio_len:len); /* Mix as much data as possible */

SDL_MixAudio(stream,audio_pos,len,SDL_MIX_MAXVOLUME);
audio_pos += len;
audio_len -= len;
}


//Thread
int sfp_refresh_thread(void *opaque)
{
while (thread_exit==0) {
SDL_Event event;
event.type = SFM_REFRESH_EVENT;
SDL_PushEvent(&event);
//Wait 40 ms
//是否是由于此处的延迟造成的、?
SDL_Delay(40);
printf("decode vedio ? audio \n");
}
return 0;
}
int main(int argc, char* argv[])
{
AVFormatContext *pFormatCtx;
int i, videoindex,audioindex;
AVCodecContext *pCodecCtx_v,*pCodecCtx_a;
AVCodec *pCodec;

//char filepath[]="src01_480x272_22.hm10";
char *filepath = "cuc_ieschool.ts";

av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();

if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){
printf("Couldn't open input stream.(无法打开输入流)\n");
return -1;
}
if(avformat_find_stream_info(pFormatCtx,NULL)<0){
printf("Couldn't find stream information.(无法获取流信息)\n");
return -1;
}

videoindex = -1,audioindex = -1;
for(i=0; i<pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoindex = i;
}else if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioindex = i;
}else
{
break;
}
}
if(videoindex == -1)
{
printf("Didn't find a video stream.(没有找到视频流)\n");
return -1;
}
if(audioindex == -1)
{
printf("Didn't find a video stream.(没有找到音频流)\n");
return -1;
}

pCodecCtx_v = pFormatCtx->streams[videoindex]->codec;
pCodec = avcodec_find_decoder(pCodecCtx_v->codec_id);
if(pCodec==NULL)
{
printf("Codec not found.(没有找到解码器)\n");
return -1;
}
if(avcodec_open2(pCodecCtx_v, pCodec,NULL)<0)
{
printf("Could not open codec.(无法打开解码器)\n");
return -1;
}

pCodecCtx_a = pFormatCtx->streams[audioindex]->codec;
pCodec=avcodec_find_decoder(pCodecCtx_a->codec_id);
if(pCodec==NULL)
{
printf("Codec not found.(没有找到解码器)\n");
return -1;
}
if(avcodec_open2(pCodecCtx_a, pCodec,NULL)<0)
{
printf("Could not open codec.(无法打开解码器)\n");
return -1;
}

AVFrame *pFrame,*pFrameYUV;
AVFrame *pFrame_a,*pFrameYUV_a;

pFrame = avcodec_alloc_frame();
pFrameYUV = avcodec_alloc_frame();

pFrame_a = avcodec_alloc_frame();
pFrameYUV_a = avcodec_alloc_frame();

uint8_t *out_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx_v->width, pCodecCtx_v->height));
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx_v->width, pCodecCtx_v->height);
//------------SDL----------------
#if 0
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))
#else
if(SDL_Init(SDL_INIT_AUDIO | SDL_INIT_TIMER))
#endif
{
printf( "Could not initialize SDL - %s\n", SDL_GetError());
return -1;
}

int screen_w=0,screen_h=0;
SDL_Surface *screen;
screen_w = pCodecCtx_v->width;
screen_h = pCodecCtx_v->height;
screen = SDL_SetVideoMode(screen_w, screen_h, 0,0);

if(!screen) {
printf("SDL: could not set video mode - exiting:%s\n",SDL_GetError());
return -1;
}
SDL_Overlay *bmp;
bmp = SDL_CreateYUVOverlay(pCodecCtx_v->width, pCodecCtx_v->height,SDL_YV12_OVERLAY, screen);
SDL_Rect rect;

int ret, got_picture;

AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));
//输出一下信息-----------------------------
printf("File Information(文件信息)---------------------\n");
av_dump_format(pFormatCtx,0,filepath,0);
printf("-------------------------------------------------\n");

//---------------------------------------------------------------------------------------------------------
//vedio

struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(pCodecCtx_v->width, pCodecCtx_v->height, pCodecCtx_v->pix_fmt, pCodecCtx_v->width, pCodecCtx_v->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
//--------------
SDL_Thread *video_tid = SDL_CreateThread(sfp_refresh_thread,NULL);
//
SDL_WM_SetCaption("Simple FFmpeg Player (SDL Update)",NULL);

//---------------------------------------------------------------------------------------------------------
//audio

uint64_t out_channel_layout=AV_CH_LAYOUT_STEREO;
int out_nb_samples=1024;
AVSampleFormat out_sample_fmt=AV_SAMPLE_FMT_S16;
int out_sample_rate=44100;
int out_channels=av_get_channel_layout_nb_channels(out_channel_layout);
//Out Buffer Size
int out_buffer_size=av_samples_get_buffer_size(NULL,out_channels ,out_nb_samples,out_sample_fmt, 1);

SDL_AudioSpec wanted_spec;
wanted_spec.freq = out_sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = out_channels;
wanted_spec.silence = 0;
wanted_spec.samples = out_nb_samples;
wanted_spec.callback = fill_audio;
wanted_spec.userdata = pCodecCtx_a;

if (SDL_OpenAudio(&wanted_spec, NULL)<0){
printf("can't open audio.\n");
return -1;
}

//先要分离,
int64_t in_channel_layout=av_get_default_channel_layout(pCodecCtx_a->channels);
//Swr
struct SwrContext *au_convert_ctx;
au_convert_ctx = swr_alloc();
au_convert_ctx = swr_alloc_set_opts(au_convert_ctx,out_channel_layout, out_sample_fmt, out_sample_rate,
in_channel_layout,pCodecCtx_a->sample_fmt , pCodecCtx_a->sample_rate,0, NULL);
swr_init(au_convert_ctx);

//Event Loop
SDL_Event event;
for (;;)
{
//Wait
//printf("begin decode\n");
SDL_WaitEvent(&event);
if(event.type==SFM_REFRESH_EVENT)
{
//------------------------------
if(av_read_frame(pFormatCtx, packet) >= 0)
{
if(packet->stream_index == videoindex)
{
ret = avcodec_decode_video2(pCodecCtx_v, pFrame, &got_picture, packet);
if(ret < 0)
{
printf("Decode Vedio Error.(视频)\n");
return -1;
//continue;//?return 为何这么样子?
}
if(got_picture)
{
sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx_v->height, pFrameYUV->data, pFrameYUV->linesize);
SDL_LockYUVOverlay(bmp);
bmp->pixels[0]=pFrameYUV->data[0];
bmp->pixels[2]=pFrameYUV->data[1];
bmp->pixels[1]=pFrameYUV->data[2];
bmp->pitches[0]=pFrameYUV->linesize[0];
bmp->pitches[2]=pFrameYUV->linesize[1];
bmp->pitches[1]=pFrameYUV->linesize[2];
SDL_UnlockYUVOverlay(bmp);
rect.x = 0;
rect.y = 0;
rect.w = screen_w;
rect.h = screen_h;
//测试自己填充数据----------------
//显示
SDL_DisplayYUVOverlay(bmp, &rect);
}
}
else if (packet->stream_index == audioindex)
{
//continue;
ret = avcodec_decode_audio4(pCodecCtx_a, pFrame_a, &got_picture, packet);
if(ret < 0)
{
printf("Decode Audio Error.(音频)\n");
return -1;
//continue;
}

if (got_picture)
{
swr_convert(au_convert_ctx,&out_buffer, MAX_AUDIO_FRAME_SIZE,(const uint8_t **)pFrame_a->data , pFrame_a->nb_samples);
if(wanted_spec.samples != pFrame_a->nb_samples){
SDL_CloseAudio();
out_nb_samples = pFrame_a->nb_samples;
out_buffer_size = av_samples_get_buffer_size(NULL,out_channels ,out_nb_samples,out_sample_fmt, 1);
wanted_spec.samples = out_nb_samples;
SDL_OpenAudio(&wanted_spec, NULL);
}

audio_chunk = (Uint8 *) out_buffer;
//Audio buffer length
audio_len = out_buffer_size;

audio_pos = audio_chunk;

//Play
SDL_PauseAudio(0);
while(audio_len>0)//Wait until finish
SDL_Delay(1);
}
}
av_free_packet(packet);
}
else
{
//Exit Thread
thread_exit = 1;
break;
}
}
}
SDL_CloseAudio();//Close SDL
SDL_Quit();

swr_free(&au_convert_ctx);
sws_freeContext(img_convert_ctx);

//--------------
av_free(out_buffer);
av_free(pFrameYUV);
avcodec_close(pCodecCtx_v);
avcodec_close(pCodecCtx_a);
avformat_close_input(&pFormatCtx);

return 0;
}



现在的问题是,这样貌似SDL播放视频也能出来,音频也能出来。
视频,能播放,但不是连续的。
音频,只能听出是“呱呱呱”的断续声音。
是什么问题呢?
...全文
570 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
Tim.Shi 2019-01-17
  • 打赏
  • 举报
回复
博主的问题找到了吗,想请教一下,遇到了同样的问题,雷霄华的MFC sample好像也是存在这样的问题,但是播放h.264的文件似乎就不存在这个问题,没有SDL_Delay,视频倒是可以正常快速的播放,实在是找不到原因
Tim.Shi 2019-01-17
  • 打赏
  • 举报
回复
我还是找出原因了,把视频显示线程中的SDL_Delay()注释掉就可以正常播放了,这里还是要感谢一下博主的代码
  • 打赏
  • 举报
回复
我去。。不小心发错版块了。版主帮我调整下谢谢。。

69,336

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧