1,451
社区成员
发帖
与我相关
我的任务
分享
#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;
}
av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, nullptr,
AV_PIX_FMT_YUV420P, pVideoCodecContext->width, pVideoCodecContext->height, 1);
搞定了,原来是上面的这句话有问题