我有一个TS格式的文件,里面有一个视频和一个音频,视频是mpeg2编码,音频是mp3编码。我使用ffmpeg库对文件进行解码,然后使用DirectDraw播放视频,使用DirectSound播放声音。现在音视频的显示和播放都没有问题了。可测试时发现,视频图像上面有很多的马赛克。我怀疑是我视频解码的操作有问题导致解码时丢数据了。自己弄了一天还是没找到原因,请大家帮忙看看,看看视频处理上是否有问题。代码如下:
C/C++ code
void CProgram::Test()
{
avcodec_init();
av_register_all();
AVFormatContext *pFormatCtx;
int i, videoStream;
int audioStream;
const char *input_file_name = "F:\\fashion_100M.ts";
// Open video file
if(av_open_input_file(&pFormatCtx, input_file_name, NULL, 0, NULL)!=0)
return ;
// Retrieve stream information
if(av_find_stream_info(pFormatCtx) < 0)
return ;
// Find the first video stream
videoStream = -1;
audioStream = -1;
for(i = 0; i < pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO)
{
videoStream = i;
}
else if(pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO)
{
audioStream = i;
}
}
if(videoStream == -1)
{
return ;
}
AVCodecContext *pVideoCodecCtx=pFormatCtx->streams[videoStream]->codec;
AVCodec *pVideoCodec=avcodec_find_decoder(pVideoCodecCtx->codec_id);
AVCodecContext *pAudioCodecCtx=pFormatCtx->streams[audioStream]->codec;
AVCodec *pAudioCodec=avcodec_find_decoder(pAudioCodecCtx->codec_id);
//通知解码器,我们能处理截断的bit流
if (pVideoCodec->capabilities&CODEC_CAP_TRUNCATED)
{
pVideoCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
}
//打开视频解码器
if(avcodec_open(pVideoCodecCtx,pVideoCodec) < 0)
{
return ;
}
//通知解码器,我们能处理截断的bit流
if (pAudioCodec->capabilities&CODEC_CAP_TRUNCATED)
{
pAudioCodecCtx->flags|=CODEC_FLAG_TRUNCATED;
}
//打开音频解码器
if(avcodec_open(pAudioCodecCtx,pAudioCodec) < 0)
{
return ;
}
uint8_t *pktdata;
int pktsize;
int out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
uint8_t * inbuf = (uint8_t *)malloc(out_size);
int nRet=0;
int nGopPicture=1;
int nFrameCount=0;
int nLostFrame=0;
AVPacket pktData;
av_init_packet(&pktData);
while(av_read_frame(pFormatCtx, &pktData) >= 0)
{
if(pktData.stream_index == videoStream)
{
AVFrame *pFrame1=avcodec_alloc_frame();
//解码视频
nRet=avcodec_decode_video(pVideoCodecCtx,pFrame1,&nGopPicture,pktData.data,pktData.size);
if ( nGopPicture > 0 )
{
//将解码出的YUV数据拷贝到自己分配的节点中
PYUV_FRAME pYUVFrame=new YUV_FRAME;
pYUVFrame->pYFrame=new unsigned char[m_stFileEncodeInfo.pVideoCodecCtx->width*m_stFileEncodeInfo.pVideoCodecCtx->height];
pYUVFrame->pUFrame=new unsigned char[m_stFileEncodeInfo.pVideoCodecCtx->width*m_stFileEncodeInfo.pVideoCodecCtx->height/4];
pYUVFrame->pVFrame=new unsigned char[m_stFileEncodeInfo.pVideoCodecCtx->width*m_stFileEncodeInfo.pVideoCodecCtx->height/4];
unsigned char *pY=pYUVFrame->pYFrame;
unsigned char *pU=pYUVFrame->pUFrame;
unsigned char *pV=pYUVFrame->pVFrame;
//拷贝Y数据
for (int i=0;i<m_stFileEncodeInfo.pVideoCodecCtx->height;i++)
{
memcpy(pY,pFrame1->data[0], m_stFileEncodeInfo.pVideoCodecCtx->width);
pFrame1->data[0]+=pFrame1->linesize[0];
pY+=m_stFileEncodeInfo.pVideoCodecCtx->width;
}
//拷贝U数据
for (int i=0;i<m_stFileEncodeInfo.pVideoCodecCtx->height/2;i++)
{
memcpy(pU,pFrame1->data[1], m_stFileEncodeInfo.pVideoCodecCtx->width/2);
pFrame1->data[1]+=pFrame1->linesize[1];
pU+=m_stFileEncodeInfo.pVideoCodecCtx->width/2;
}
//拷贝V数据
for (int i=0;i<m_stFileEncodeInfo.pVideoCodecCtx->height/2;i++)
{
memcpy(pV,pFrame1->data[2], m_stFileEncodeInfo.pVideoCodecCtx->width/2);
pFrame1->data[2]+=pFrame1->linesize[2];
pV+=m_stFileEncodeInfo.pVideoCodecCtx->width/2;
}
//将节点保存到链表中供DirectDraw显示
m_videoPlay.m_csVideoQueueSection.Lock();
m_videoPlay.m_listVideoFrame.AddTail(pYUVFrame);
m_videoPlay.m_csVideoQueueSection.Unlock();
nFrameCount++;
TRACE("nGopPicture > 0 成功解码! %d 帧,nGopPicture值为 %d ,nRet值为 %d ,输入包长为 %d \n",nFrameCount,nGopPicture,nRet,pktData.size);
}
else
{
nLostFrame++;
TRACE("-----丢失帧的总数为 %d ,nGopPicture值为 %d ,nRet值为 %d,输入包长为 %d----\n",nLostFrame,nGopPicture,nRet,pktData.size);
}
av_free(pFrame1);
}
else if(pktData.stream_index == audioStream)
{
//解码音频
int nInSize=pktData.size;
unsigned char *pInBuff=pktData.data;
int outSize=AVCODEC_MAX_AUDIO_FRAME_SIZE;
unsigned char *pOutBuff=new unsigned char[outSize];
memset(pOutBuff,0,AVCODEC_MAX_AUDIO_FRAME_SIZE);
nRet=avcodec_decode_audio2(m_stFileEncodeInfo.pAudioCodecCtx,(short*)pOutBuff,&outSize,pInBuff,nInSize);
if (nRet >= 0)
{
//将解码得到的PCM数据保存到缓冲区中中供DirectSound播放
m_audioPlay.m_audioRingBuff.InputData(pOutBuff,outSize);
}
delete[] pOutBuff;
pOutBuff=NULL;
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&pktData);
}
av_close_input_file(pFormatCtx);
};