Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
470 lines (370 sloc) 12.4 KB
#include "Player.hpp"
using namespace std;
//struct para audio
struct SwrContext *swrCtx = NULL;
AVFrame wanted_frame;
AudioPacket audioq;
void audio_callback(void*, Uint8*, int);
//exibe informa��o dos streams do arquivo de v�deo espec�fico
void Player::exibirInformacaoArquivoVideo(void) {
av_dump_format(pFormatCtx, 0, pFormatCtx->filename, 0);
}
//exibe o erro, descrevendo-o
void Player::exibirErro(int erro) {
char errobuf[ERROR_SIZE];
av_strerror(erro, errobuf, ERROR_SIZE);
cout << "Erro = " << errobuf<<endl;
}
//obtem o stream do video
int Player::obterCodecParameters(void) {
int videoStream = -1;
for (unsigned int i = 0; i<pFormatCtx->nb_streams; i++){
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) videoStream = i;
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) audioStream = i;
}
if (videoStream == -1) {
cout << "Nao achou o stream" << endl;
return -1;
}
pCodecParameters = pFormatCtx->streams[videoStream]->codecpar;
if(audioStream != -1) pCodecAudioParameters = pFormatCtx->streams[audioStream]->codecpar;
return videoStream;
}
//ler o codec do stream em quest�o, do v�deo lido
int Player::lerCodecVideo(void) {
//v� se o codec � suportado
pCodec = avcodec_find_decoder(pCodecParameters->codec_id);
pAudioCodec = avcodec_find_decoder(pCodecAudioParameters->codec_id);
if (pCodec == NULL) {
cout << " bad video codec " << endl;
return -1; // Codec not found
}
if (pAudioCodec == NULL) {
cout << " bad audio codec " << endl;
return -1; // Codec not found
}
//cria uma estrutura AVCodecContext alocada com o codec em quest�o
pCodecCtx = avcodec_alloc_context3(pCodec);
if(pCodecCtx == NULL){
cout<<"Bad video codec"<<endl;
exit(-1);
}
pCodecAudioCtx = avcodec_alloc_context3(pAudioCodec);
if(pCodecAudioCtx == NULL){
cout<<"Bad audio codec"<<endl;
exit(-1);
}
//copia os par�metros originais do v�deo de pCodecParameters para o codecContext
int res = avcodec_parameters_to_context(pCodecCtx, pCodecParameters);
if(res < 0){
cout<<"Failed to get video codec"<<endl;
avformat_close_input(&pFormatCtx);
avcodec_free_context(&pCodecCtx);
exit(-1);
}
//copia os par�metros originais do audio de pCodecParameters para o codecContext
res = avcodec_parameters_to_context(pCodecAudioCtx, pCodecAudioParameters);
if (res < 0) {
cout<<"Failed to get audio codec"<<endl;
avformat_close_input(&pFormatCtx);
avcodec_free_context(&pCodecCtx);
avcodec_free_context(&pCodecAudioCtx);
exit(-1);
}
//executa o codec
res = avcodec_open2(pCodecCtx, pCodec, NULL);
if(res < 0){
cout<<"Failed to open video codec"<<endl;
exit(-1);
}
res = avcodec_open2(pCodecAudioCtx, pAudioCodec, NULL);
if (res < 0) {
cout<<"Failed to open audio codec"<<endl;
exit(-1);
}
return 1;
}
//aloca a mem�ria de acordo com o tamanho do v�deo
int Player::alocarMemoria(void) {
swrCtx = swr_alloc();
if(swrCtx == NULL){
cout<<"Failed to load audio"<<endl;
exit(-1);
}
//audio context
av_opt_set_channel_layout(swrCtx, "in_channel_layout", pCodecAudioCtx->channel_layout, 0);
av_opt_set_channel_layout(swrCtx, "out_channel_layout", pCodecAudioCtx->channel_layout, 0);
av_opt_set_int(swrCtx, "in_sample_rate", pCodecAudioCtx->sample_rate, 0);
av_opt_set_int(swrCtx, "out_sample_rate", pCodecAudioCtx->sample_rate, 0);
av_opt_set_sample_fmt(swrCtx, "in_sample_fmt", pCodecAudioCtx->sample_fmt, 0);
av_opt_set_sample_fmt(swrCtx, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0);
int res = swr_init(swrCtx);
if(res != 0){
cout<<"Failed to initialize audio"<<endl;
exit(-1);
}
memset(&wantedSpec, 0, sizeof(wantedSpec));
wantedSpec.channels = pCodecAudioCtx->channels;
wantedSpec.freq = pCodecAudioCtx->sample_rate;
wantedSpec.format = AUDIO_S16SYS;
wantedSpec.silence = 0;
wantedSpec.samples = SDL_AUDIO_BUFFER_SIZE;
wantedSpec.userdata = pCodecAudioCtx;
wantedSpec.callback = audio_callback;
if (SDL_OpenAudio(&wantedSpec, &audioSpec) < 0) {
cout<<"Error opening audio"<<endl;
exit(-1);
}
wanted_frame.format = AV_SAMPLE_FMT_S16;
wanted_frame.sample_rate = audioSpec.freq;
wanted_frame.channel_layout = av_get_default_channel_layout(audioSpec.channels);
wanted_frame.channels = audioSpec.channels;
initAudioPacket(&audioq);
SDL_PauseAudio(0);
pFrame = av_frame_alloc();
if (pFrame == NULL) {
cout << "N�o foi possivel alocar a memoria do frame" << endl;
return -1;
}
pFrameRGB = av_frame_alloc();
if (pFrameRGB == NULL) {
cout << "N�o foi possivel alocar a memoria do frame RGB" << endl;
return -1;
}
//ver essa quest�o do formato escolhido RGB24 ou YUV420p
int numBytes = av_image_get_buffer_size(FORMATO, pCodecCtx->width, pCodecCtx->height,1);
cout << "qtd bytes="<<numBytes << endl;
//cria a mem�ria necess�ria para o buffer
buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
//associa o buffer ao Frame
res = av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, FORMATO, pCodecCtx->width, pCodecCtx->height, 1);
if (res < 0) {
exibirErro(res);
return res;
}
return 1;
}
void Player::initAudioPacket(AudioPacket *q)
{
q->last = NULL;
q->first = NULL;
q->mutex = SDL_CreateMutex();
q->cond = SDL_CreateCond();
}
int Player::putAudioPacket(AudioPacket *q, AVPacket *pkt)
{
AVPacketList *pktl;
AVPacket *newPkt;
newPkt = (AVPacket*)av_mallocz_array(1, sizeof(AVPacket));
if (av_packet_ref(newPkt, pkt) < 0)
return -1;
pktl = (AVPacketList*)av_malloc(sizeof(AVPacketList));
if (!pktl)
return -1;
pktl->pkt = *newPkt;
pktl->next = NULL;
SDL_LockMutex(q->mutex);
if (!q->last)
q->first = pktl;
else
q->last->next = pktl;
q->last = pktl;
q->nb_packets++;
q->size += newPkt->size;
SDL_CondSignal(q->cond);
SDL_UnlockMutex(q->mutex);
return 0;
}
int Player::getAudioPacket(AudioPacket* q, AVPacket* pkt, int block){
AVPacketList* pktl;
int ret;
SDL_LockMutex(q->mutex);
while (1)
{
pktl = q->first;
if (pktl)
{
q->first = pktl->next;
if (!q->first)
q->last = NULL;
q->nb_packets--;
q->size -= pktl->pkt.size;
*pkt = pktl->pkt;
av_free(pktl);
ret = 1;
break;
}
else if (!block)
{
ret = 0;
break;
}
else
{
SDL_CondWait(q->cond, q->mutex);
}
}
SDL_UnlockMutex(q->mutex);
return ret;
}
int audio_decode_frame(AVCodecContext* aCodecCtx, uint8_t* audio_buf, int buf_size){
static AVPacket pkt;
static uint8_t* audio_pkt_data = NULL;
static int audio_pkt_size = 0;
static AVFrame frame;
int len1;
int data_size = 0;
SwrContext* swr_ctx = NULL;
while (1)
{
while (audio_pkt_size > 0)
{
int got_frame = 0;
avcodec_send_packet(aCodecCtx, &pkt);
avcodec_receive_frame(aCodecCtx, &frame);
len1 = frame.pkt_size;
if (len1 < 0)
{
audio_pkt_size = 0;
break;
}
audio_pkt_data += len1;
audio_pkt_size -= len1;
data_size = 0;
if (got_frame)
{
int linesize = 1;
data_size = av_samples_get_buffer_size(&linesize, aCodecCtx->channels, frame.nb_samples, aCodecCtx->sample_fmt, 1);
assert(data_size <= buf_size);
memcpy(audio_buf, frame.data[0], data_size);
}
if (frame.channels > 0 && frame.channel_layout == 0)
frame.channel_layout = av_get_default_channel_layout(frame.channels);
else if (frame.channels == 0 && frame.channel_layout > 0)
frame.channels = av_get_channel_layout_nb_channels(frame.channel_layout);
if (swr_ctx)
{
swr_free(&swr_ctx);
swr_ctx = NULL;
}
swr_ctx = swr_alloc_set_opts(NULL, wanted_frame.channel_layout, (AVSampleFormat) wanted_frame.format, wanted_frame.sample_rate,
frame.channel_layout, (AVSampleFormat) frame.format, frame.sample_rate, 0, NULL);
if (!swr_ctx || swr_init(swr_ctx) < 0)
{
cout<<"swr_init failed"<<endl;
break;
}
int dst_nb_samples = (int)av_rescale_rnd(swr_get_delay(swr_ctx, frame.sample_rate) + frame.nb_samples,
wanted_frame.sample_rate, wanted_frame.format, AV_ROUND_INF);
int len2 = swr_convert(swr_ctx, &audio_buf, dst_nb_samples,
(const uint8_t**)frame.data, frame.nb_samples);
if (len2 < 0)
{
cout<<"swr_convert failed"<<endl;
break;
}
return wanted_frame.channels * len2 * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
if (data_size <= 0)
continue;
return data_size;
}
if (pkt.data)
av_packet_unref(&pkt);
if (Player::getAudioPacket(&audioq, &pkt, 1) < 0)
return -1;
audio_pkt_data = pkt.data;
audio_pkt_size = pkt.size;
}
}
void audio_callback(void* userdata, Uint8* stream, int len){
AVCodecContext* aCodecCtx = (AVCodecContext*)userdata;
int len1, audio_size;
static uint8_t audio_buff[192000 * 3 / 2];
static unsigned int audio_buf_size = 0;
static unsigned int audio_buf_index = 0;
SDL_memset(stream, 0, len);
while (len > 0)
{
if (audio_buf_index >= audio_buf_size)
{
audio_size = audio_decode_frame(aCodecCtx, audio_buff, sizeof(audio_buff));
if (audio_size < 0)
{
audio_buf_size = 1024;
memset(audio_buff, 0, audio_buf_size);
}
else
audio_buf_size = audio_size;
audio_buf_index = 0;
}
len1 = audio_buf_size - audio_buf_index;
if (len1 > len)
len1 = len;
SDL_MixAudio(stream, audio_buff + audio_buf_index, len, SDL_MIX_MAXVOLUME);
//memcpy(stream, (uint8_t*)(audio_buff + audio_buf_index), audio_buf_size);
len -= len1;
stream += len1;
audio_buf_index += len1;
}
}
//L� a "data" que vem do stream de v�deo
int Player::lerFramesVideo(void) {
AVPacket packet;
//video context
sws_ctx = sws_getContext(pCodecCtx->width,
pCodecCtx->height,
pCodecCtx->pix_fmt,
pCodecCtx->width,
pCodecCtx->height,
FORMATO,
SWS_BILINEAR,
NULL,
NULL,
NULL
);
SDL_Event evt;
//lendo e colocando no packet
while (av_read_frame(pFormatCtx, &packet) >= 0) {
if (packet.stream_index == audioStream) {
putAudioPacket(&audioq, &packet);
}
//verifica��o se foi transmitido pelo Stream do Context
if (packet.stream_index == videoStream) {
//processo de decodifica��o
int res = avcodec_send_packet(pCodecCtx, &packet);
if (res < 0) {
exibirErro(res);
continue;
}
res = avcodec_receive_frame(pCodecCtx, pFrame);
if (res < 0) {
exibirErro(res);
continue;
}
SDL_UpdateYUVTexture(bmp, NULL, pFrame->data[0], pFrame->linesize[0],
pFrame->data[1], pFrame->linesize[1],
pFrame->data[2], pFrame->linesize[2]);
SDL_RenderCopy(renderer, bmp, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_UpdateWindowSurface(screen);
SDL_Delay(1000/30);
}
//av_packet_unref(&packet);
SDL_PollEvent(&evt);
}
return 1;
}
int Player::criarDisplay(void) {
screen = SDL_CreateWindow("Video Player teste",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
pCodecCtx->width, pCodecCtx->height,
SDL_WINDOW_OPENGL);
if (!screen) {
cout << "N�o foi possivel setar a screen com o v�deo desse tamannho" << endl;
return -1;
}
renderer = SDL_CreateRenderer(screen, -1, 0);
bmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STATIC, pCodecCtx->width, pCodecCtx->height);
return 1;
}