FFMPEG 无法显示YUV图像

红色代码 2016-06-28 07:28:26
不好意思,直接上代码了.问题是用avcodec_decode_video2解码出一帧原始数据可以绘出图像,但是用sws_scale转换YUV数据后就是绿油油一片,哪里出问题了?

#include "StdAfx.h"
#include "MediaPlayer.h"
#include <atlconv.h>


Uint8* CMediaPlayer::m_pAudioPos = nullptr;
Uint32 CMediaPlayer::m_nAudioLen = 0;

CMediaPlayer::CMediaPlayer(void): m_pFrameContext(nullptr),
m_hReadFrameThread(nullptr),
m_bReadFrameThreadExit(false),
m_pSdlWindow(nullptr),
m_pSdlRenderer(nullptr),
m_pSdlTexture(nullptr),
m_pSwsContext(nullptr)
{
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
}

CMediaPlayer::~CMediaPlayer(void)
{
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
}

//---------------------------------------------------------------------------------
void CMediaPlayer::Release()
{
}

//---------------------------------------------------------------------------------
bool CMediaPlayer::Open(const TCHAR* sUrl)
{
if (nullptr == sUrl)
return false;

av_register_all();
USES_CONVERSION;
const char* sAnsiUrl = W2A(sUrl);
if (nullptr == m_pFrameContext)
m_pFrameContext = avformat_alloc_context();

if (avformat_open_input(&m_pFrameContext, sAnsiUrl, nullptr, nullptr) < 0)
return false;

if (avformat_find_stream_info(m_pFrameContext, nullptr) < 0)
return false;

int nBestStreamIndex = -1;
int nStream = m_pFrameContext->nb_streams;
for (int i = 0; i < nStream; i++)
{
AVStream* pStream = m_pFrameContext->streams[i];
if (nullptr == pStream) continue;

AVCodecContext* pCodecContext = pStream->codec;
if (nullptr == pCodecContext) continue;

AVCodec* pCodec = avcodec_find_decoder(pCodecContext->codec_id);
if (nullptr == pCodec) continue;

nBestStreamIndex = av_find_best_stream(m_pFrameContext, pCodec->type, -1, -1, nullptr, 0);
if (i != nBestStreamIndex)
continue;

if (avcodec_open2(pCodecContext, pCodec, nullptr) < 0)
continue;

m_codecContexts.push_back(pStream);
}

// 初始化视频设备
AVCodecContext* pVideoCodecContext = FindCodecContext(AVMEDIA_TYPE_VIDEO);
int nScreenWidth = pVideoCodecContext->width;
int nScreenHeight = pVideoCodecContext->height;

m_pSwsContext = sws_getContext(nScreenWidth, nScreenHeight, pVideoCodecContext->pix_fmt,
nScreenWidth, nScreenHeight, AV_PIX_FMT_YUV420P,
SWS_BICUBIC, nullptr, nullptr, nullptr);

if (nullptr == m_pSdlWindow)
m_pSdlWindow = SDL_CreateWindow("My VPlayer",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, nScreenWidth, nScreenHeight, SDL_WINDOW_OPENGL);
if (nullptr == m_pSdlWindow) return false;

if (nullptr == m_pSdlRenderer)
m_pSdlRenderer = SDL_CreateRenderer(m_pSdlWindow, -1, 0);
if (nullptr == m_pSdlRenderer) return false;

if (nullptr == m_pSdlTexture)
m_pSdlTexture = SDL_CreateTexture(m_pSdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, nScreenWidth, nScreenHeight);
if (nullptr == m_pSdlTexture) return false;

int nLayoutNbChannels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
// 打开声音设备
AVCodecContext* pAudioCodecContext = FindCodecContext(AVMEDIA_TYPE_AUDIO);
if (nullptr != pAudioCodecContext)
{
SDL_AudioSpec sdlAudioSpec = {0};
sdlAudioSpec.freq = 44100;
sdlAudioSpec.samples = pAudioCodecContext->frame_size;
sdlAudioSpec.channels = nLayoutNbChannels;;
sdlAudioSpec.format = AUDIO_S16SYS ;
sdlAudioSpec.silence = 0;
sdlAudioSpec.callback = SDL_AudioCallback;
sdlAudioSpec.userdata = nullptr;

if (-1 == SDL_OpenAudio(&sdlAudioSpec, nullptr))
return false;

m_nAudioLen = av_samples_get_buffer_size(nullptr, nLayoutNbChannels, pAudioCodecContext->frame_size, AV_SAMPLE_FMT_S16, 1);
}

if (nullptr == m_hReadFrameThread)
m_hReadFrameThread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)_ReadFrameThread, this, 0, nullptr);
if (nullptr == m_hReadFrameThread)
return false;

return true;
}

//---------------------------------------------------------------------------------
void CMediaPlayer::Close()
{
if (nullptr != m_hReadFrameThread)
{
m_bReadFrameThreadExit = true;
WaitForSingleObject(m_hReadFrameThread,INFINITE);
CloseHandle(m_hReadFrameThread);
m_hReadFrameThread = nullptr;
}

SDL_CloseAudio();

if (nullptr != m_pSwsContext)
{
sws_freeContext(m_pSwsContext);
m_pSwsContext = nullptr;
}

if (nullptr != m_pSdlTexture)
{
SDL_DestroyTexture(m_pSdlTexture);
m_pSdlTexture = nullptr;
}

if (nullptr != m_pSdlRenderer)
{
SDL_DestroyRenderer(m_pSdlRenderer);
m_pSdlRenderer = nullptr;
}

if (nullptr != m_pSdlWindow)
{
SDL_DestroyWindow(m_pSdlWindow);
m_pSdlWindow = nullptr;
}

CODEC_CONTEXTS::const_iterator cit = m_codecContexts.begin();
for (cit; cit != m_codecContexts.end(); ++cit)
{
AVStream* pStream = *cit;
if (nullptr == pStream) continue;
AVCodecContext* pCodecContext = pStream->codec;
if (nullptr == pCodecContext) continue;
avcodec_close(pCodecContext);
pCodecContext = nullptr;
}

m_codecContexts.clear();

if (nullptr != m_pFrameContext)
{
avformat_close_input(&m_pFrameContext);
avformat_free_context(m_pFrameContext);
m_pFrameContext = nullptr;
}
}

//---------------------------------------------------------------------------------
void CMediaPlayer::Pause()
{
}

//---------------------------------------------------------------------------------
void CMediaPlayer::Resume()
{
}

//---------------------------------------------------------------------------------
void CMediaPlayer::Seek(long nTime)
{
}

//---------------------------------------------------------------------------------
unsigned long __stdcall CMediaPlayer::_ReadFrameThread(CMediaPlayer* pThis)
{
if (nullptr == pThis)
return -1;

return pThis->ReadFrameLoop();
}

//---------------------------------------------------------------------------------
unsigned long CMediaPlayer::ReadFrameLoop()
{
AVCodecContext* pVideoCodecContext = FindCodecContext(AVMEDIA_TYPE_VIDEO);
AVCodecContext* pAudioCodecContext = FindCodecContext(AVMEDIA_TYPE_AUDIO);
AVCodecContext* pSubTitleCodecContext = FindCodecContext(AVMEDIA_TYPE_SUBTITLE);

int nVideoStreamIndex = FindCodecStreamIndex(AVMEDIA_TYPE_VIDEO);
int nAudioStreamIndex = FindCodecStreamIndex(AVMEDIA_TYPE_AUDIO);
int nSubTitleStreamIndex = FindCodecStreamIndex(AVMEDIA_TYPE_SUBTITLE);
int got_picture = 0;
AVPacket pkt = {nullptr};
av_init_packet(&pkt);

AVFrame* frame = av_frame_alloc();
AVFrame* pFrameYUV = av_frame_alloc();
av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, nullptr,
AV_PIX_FMT_YUV420P, pVideoCodecContext->width, pVideoCodecContext->height, 1);

while (!m_bReadFrameThreadExit)
{
while (av_read_frame(m_pFrameContext, &pkt) >= 0 && (!m_bReadFrameThreadExit))
{
if (pkt.stream_index == nVideoStreamIndex)
{
if (avcodec_decode_video2(pVideoCodecContext, frame, &got_picture, &pkt) < 0)
{
_tprintf(_T("Decode Video Failed\r\n"));
return -1;
}

if (got_picture <= 0) continue;

// 显示图像
sws_scale(m_pSwsContext, (const unsigned char* const*)frame->data,
frame->linesize, 0, pVideoCodecContext->height,
pFrameYUV->data, pFrameYUV->linesize);

SDL_UpdateTexture(m_pSdlTexture, nullptr, pFrameYUV->data[0], pFrameYUV->linesize[0]);
SDL_RenderClear(m_pSdlRenderer);
SDL_RenderCopy(m_pSdlRenderer, m_pSdlTexture, nullptr, nullptr);
SDL_RenderPresent(m_pSdlRenderer);
}
else if (pkt.stream_index == nAudioStreamIndex)
{
if (avcodec_decode_audio4(pAudioCodecContext, frame, &got_picture, &pkt) < 0)
{
_tprintf(_T("Decode Audio Failed\r\n"));
return -2;
}

if (0 == got_picture) continue;

m_pAudioPos = (Uint8*)frame->data;
}
}
}

if (nullptr != pFrameYUV)
{
av_frame_free(&pFrameYUV);
pFrameYUV = nullptr;
}

if (nullptr != frame)
{
av_frame_free(&frame);
frame = nullptr;
}

av_free_packet(&pkt);

return 0;
}

//---------------------------------------------------------------------------------
AVCodecContext* CMediaPlayer::FindCodecContext(AVMediaType mediaType)
{
AVCodecContext* pContext = nullptr;
CODEC_CONTEXTS::const_iterator cit = m_codecContexts.begin();
for (cit; cit != m_codecContexts.end(); ++cit)
{
AVStream* pStream = *cit;
if (nullptr == pStream) continue;

AVCodecContext* pCodecContext = pStream->codec;
if (nullptr == pCodecContext) continue;
if (pCodecContext->codec->type == mediaType)
{
pContext = pCodecContext;
break;
}
}

return pContext;
}

//---------------------------------------------------------------------------------
int CMediaPlayer::FindCodecStreamIndex(AVMediaType mediaType)
{
int nStreamIndex = -1;
CODEC_CONTEXTS::const_iterator cit = m_codecContexts.begin();
for (cit; cit != m_codecContexts.end(); ++cit)
{
AVStream* pStream = *cit;
if (nullptr == pStream) continue;

AVCodecContext* pCodecContext = pStream->codec;
if (nullptr == pCodecContext) continue;
if (pCodecContext->codec->type == mediaType)
{
nStreamIndex = pStream->index;
break;
}
}

return nStreamIndex;
}

//---------------------------------------------------------------------------------
void CMediaPlayer::SDL_AudioCallback(void* userdata, Uint8* stream, int len)
{
if (m_nAudioLen <= 0) return;

SDL_MixAudio(stream, m_pAudioPos, len,SDL_MIX_MAXVOLUME);
m_pAudioPos += len;
m_nAudioLen -= len;
}

...全文
386 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
红色代码 2016-06-29
  • 打赏
  • 举报
回复
av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, nullptr,
                         AV_PIX_FMT_YUV420P, pVideoCodecContext->width, pVideoCodecContext->height, 1);
搞定了,原来是上面的这句话有问题

1,451

社区成员

发帖
与我相关
我的任务
社区描述
多媒体/设计/Flash/Silverlight 开发 图象工具使用
社区管理员
  • 图象工具使用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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