Replace deprecated ffmpeg functions and types
Refactor and update decoding functions. Use absolute frame times to maintain consistent video FPS.
This commit is contained in:
parent
628a27b38b
commit
3c3b436cc1
1 changed files with 334 additions and 324 deletions
352
src/bink.c
352
src/bink.c
|
@ -7,10 +7,12 @@
|
|||
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include "libavcodec/avcodec.h"
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libavutil/avutil.h"
|
||||
#include "libavutil/imgutils.h"
|
||||
#include "libavutil/channel_layout.h"
|
||||
#include "libswscale/swscale.h"
|
||||
|
||||
|
@ -34,20 +36,20 @@ extern float PlatVolumeToGain(int volume);
|
|||
struct binkMovie
|
||||
{
|
||||
AVFormatContext* avContext;
|
||||
AVPacket packet;
|
||||
|
||||
int videoStreamIndex;
|
||||
AVCodec* videoCodec;
|
||||
AVCodecContext* videoCodecContext;
|
||||
AVFrame* videoFrame;
|
||||
struct SwsContext* videoScaleContext;
|
||||
AVPicture videoScalePicture;
|
||||
uint8_t* videoScalePicture[4];
|
||||
int videoScaleLineSize[4];
|
||||
uint videoScaleWidth;
|
||||
uint videoScaleHeight;
|
||||
uint videoScaleFormat;
|
||||
float videoFrameRate;
|
||||
enum AVPixelFormat videoScaleFormat;
|
||||
float videoFrameDuration;
|
||||
|
||||
int audioStreamIndex;
|
||||
AVCodec* audioCodec;
|
||||
AVCodecContext* audioCodecContext;
|
||||
AVFrame* audioFrame;
|
||||
char* audioTempBuffer;
|
||||
|
@ -61,7 +63,7 @@ struct binkMovie
|
|||
ALenum alFormat;
|
||||
ALuint alSampleRate;
|
||||
|
||||
uint timeLastUpdate;
|
||||
uint timeStart;
|
||||
|
||||
BOOL looping;
|
||||
BOOL isfmv;
|
||||
|
@ -70,27 +72,29 @@ struct binkMovie
|
|||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
void BinkRenderMovie(struct binkMovie* aMovie)
|
||||
static void BinkRenderMovie(struct binkMovie* aMovie)
|
||||
{
|
||||
if(aMovie && aMovie->videoFrame && aMovie->videoScalePicture.data[0])
|
||||
if(aMovie && aMovie->videoFrame && aMovie->videoScalePicture[0])
|
||||
{
|
||||
DrawAvpMenuBink(
|
||||
aMovie->videoScalePicture.data[0],
|
||||
aMovie->videoScalePicture[0],
|
||||
aMovie->videoFrame->width,
|
||||
aMovie->videoFrame->height,
|
||||
aMovie->videoScalePicture.linesize[0]);
|
||||
aMovie->videoScaleLineSize[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BinkInitMovieStruct(struct binkMovie* aMovie)
|
||||
static void BinkInitMovieStruct(struct binkMovie* aMovie)
|
||||
{
|
||||
memset((void*)aMovie, 0, sizeof(struct binkMovie));
|
||||
aMovie->videoStreamIndex = -1;
|
||||
aMovie->audioStreamIndex = -1;
|
||||
*aMovie = (struct binkMovie){
|
||||
.audioStreamIndex = -1,
|
||||
.videoStreamIndex = -1,
|
||||
.videoScaleFormat = AV_PIX_FMT_NONE,
|
||||
};
|
||||
}
|
||||
|
||||
void BinkReleaseMovie(struct binkMovie* aMovie)
|
||||
static void BinkReleaseMovie(struct binkMovie* aMovie)
|
||||
{
|
||||
if(aMovie->alInited)
|
||||
{
|
||||
|
@ -102,135 +106,66 @@ void BinkReleaseMovie(struct binkMovie* aMovie)
|
|||
}
|
||||
|
||||
if(aMovie->videoScaleContext)
|
||||
avpicture_free(&aMovie->videoScalePicture);
|
||||
av_freep(&aMovie->videoScalePicture[0]);
|
||||
|
||||
if(aMovie->avContext)
|
||||
avformat_close_input(&aMovie->avContext);
|
||||
if(aMovie->audioCodecContext)
|
||||
avcodec_free_context(&aMovie->audioCodecContext);
|
||||
if(aMovie->audioFrame)
|
||||
av_frame_free(&aMovie->audioFrame);
|
||||
if(aMovie->videoCodecContext)
|
||||
avcodec_free_context(&aMovie->videoCodecContext);
|
||||
if(aMovie->videoFrame)
|
||||
av_frame_free(&aMovie->videoFrame);
|
||||
|
||||
BinkInitMovieStruct(aMovie);
|
||||
}
|
||||
|
||||
|
||||
int BinkStartMovie(struct binkMovie* aMovie, const char* aFilename, BOOL aLoopFlag, BOOL aFmvFlag, BOOL aMusicFlag)
|
||||
{
|
||||
BinkInitMovieStruct(aMovie);
|
||||
aMovie->looping = aLoopFlag;
|
||||
|
||||
if(aFmvFlag)
|
||||
{
|
||||
aMovie->videoScaleWidth = 128;
|
||||
aMovie->videoScaleHeight = 96;
|
||||
aMovie->videoScaleFormat = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
|
||||
if(avformat_open_input(&aMovie->avContext, aFilename, NULL, NULL) < 0)
|
||||
static int DecodeVideoFrame(struct binkMovie* aMovie)
|
||||
{
|
||||
int ret = avcodec_receive_frame(aMovie->videoCodecContext, aMovie->videoFrame);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!avformat_find_stream_info(aMovie->avContext, NULL) < 0)
|
||||
{
|
||||
BinkReleaseMovie(aMovie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numStreams = 0;
|
||||
for(int i=0; i<aMovie->avContext->nb_streams; i++)
|
||||
{
|
||||
AVCodecContext* codec_context = aMovie->avContext->streams[i]->codec;
|
||||
AVCodec* codec = avcodec_find_decoder(codec_context->codec_id);
|
||||
if(codec)
|
||||
{
|
||||
if((codec_context->codec_type==AVMEDIA_TYPE_VIDEO && aMovie->videoStreamIndex>=0) || (codec_context->codec_type==AVMEDIA_TYPE_AUDIO && aMovie->audioStreamIndex>=0))
|
||||
continue;
|
||||
|
||||
if(avcodec_open2(codec_context, codec, 0) < 0)
|
||||
continue;
|
||||
|
||||
if(codec_context->codec_type==AVMEDIA_TYPE_VIDEO && !aMusicFlag)
|
||||
{
|
||||
aMovie->videoCodec = codec;
|
||||
aMovie->videoCodecContext = codec_context;
|
||||
aMovie->videoStreamIndex = i;
|
||||
aMovie->videoFrame = av_frame_alloc();
|
||||
numStreams++;
|
||||
|
||||
aMovie->videoFrameRate = (float)aMovie->avContext->streams[i]->avg_frame_rate.num / (float)aMovie->avContext->streams[i]->avg_frame_rate.den;
|
||||
}
|
||||
if(codec_context->codec_type==AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
aMovie->audioCodec = codec;
|
||||
aMovie->audioCodecContext = codec_context;
|
||||
aMovie->audioStreamIndex = i;
|
||||
aMovie->audioFrame = av_frame_alloc();
|
||||
numStreams++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(aMovie->videoStreamIndex < 0 && aMovie->audioStreamIndex < 0)
|
||||
{
|
||||
BinkReleaseMovie(aMovie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!aFmvFlag)
|
||||
{
|
||||
for(int i=0; i<(FRAMEQUEUESIZE-1) * numStreams; i++)
|
||||
BinkDecodeFrame(aMovie);
|
||||
}
|
||||
|
||||
aMovie->timeLastUpdate = SDL_GetTicks();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int BinkDecodeFrameInternal(struct binkMovie* aMovie, AVPacket* aPacket)
|
||||
{
|
||||
// decode video frame
|
||||
if(aPacket->stream_index == aMovie->videoStreamIndex)
|
||||
{
|
||||
int decoded_frame_ready = 0;
|
||||
int len = avcodec_decode_video2(aMovie->videoCodecContext, aMovie->videoFrame, &decoded_frame_ready, aPacket);
|
||||
if(len<0)
|
||||
return aMovie->looping;
|
||||
|
||||
if(decoded_frame_ready<1)
|
||||
return 1;
|
||||
|
||||
if(aMovie->videoScaleContext==NULL)
|
||||
{
|
||||
if(aMovie->videoScaleWidth==0) aMovie->videoScaleWidth = aMovie->videoFrame->width;
|
||||
if(aMovie->videoScaleHeight==0) aMovie->videoScaleHeight = aMovie->videoFrame->height;
|
||||
if(aMovie->videoScaleFormat==0) aMovie->videoScaleFormat = AV_PIX_FMT_RGB565;
|
||||
if(aMovie->videoScaleFormat==AV_PIX_FMT_NONE) aMovie->videoScaleFormat = AV_PIX_FMT_RGB565;
|
||||
|
||||
aMovie->videoScaleContext = sws_getContext(
|
||||
aMovie->videoFrame->width, aMovie->videoFrame->height, aMovie->videoFrame->format,
|
||||
aMovie->videoScaleWidth, aMovie->videoScaleHeight, aMovie->videoScaleFormat,
|
||||
aMovie->videoFrame->width, aMovie->videoFrame->height,
|
||||
aMovie->videoFrame->format,
|
||||
aMovie->videoScaleWidth, aMovie->videoScaleHeight,
|
||||
aMovie->videoScaleFormat,
|
||||
SWS_FAST_BILINEAR, NULL, NULL, NULL);
|
||||
|
||||
if (aMovie->videoScaleContext==NULL)
|
||||
return 0;
|
||||
|
||||
avpicture_alloc(&aMovie->videoScalePicture, aMovie->videoScaleFormat, aMovie->videoScaleWidth, aMovie->videoScaleHeight);
|
||||
av_image_alloc(aMovie->videoScalePicture, aMovie->videoScaleLineSize,
|
||||
aMovie->videoScaleWidth, aMovie->videoScaleHeight,
|
||||
aMovie->videoScaleFormat, 1);
|
||||
}
|
||||
|
||||
sws_scale(aMovie->videoScaleContext, aMovie->videoFrame->data, aMovie->videoFrame->linesize, 0, aMovie->videoFrame->height, aMovie->videoScalePicture.data, aMovie->videoScalePicture.linesize);
|
||||
sws_scale(aMovie->videoScaleContext,
|
||||
(const uint8_t* const*)aMovie->videoFrame->data,
|
||||
aMovie->videoFrame->linesize, 0, aMovie->videoFrame->height,
|
||||
aMovie->videoScalePicture, aMovie->videoScaleLineSize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// decode audio frame
|
||||
else if(aPacket->stream_index == aMovie->audioStreamIndex)
|
||||
static int DecodeAudioFrame(struct binkMovie* aMovie)
|
||||
{
|
||||
|
||||
int packageSize= aPacket->size;
|
||||
|
||||
int decoded_frame_ready = 0;
|
||||
av_frame_unref(aMovie->audioFrame);
|
||||
//avcodec_get_frame_defaults(aMovie->audioFrame);
|
||||
|
||||
int len = avcodec_decode_audio4(aMovie->audioCodecContext, aMovie->audioFrame, &decoded_frame_ready, aPacket);
|
||||
if(len<0)
|
||||
return aMovie->looping;
|
||||
int ret = avcodec_receive_frame(aMovie->audioCodecContext, aMovie->audioFrame);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if(!SoundSys_IsOn())
|
||||
return 0;
|
||||
|
@ -274,7 +209,6 @@ int BinkDecodeFrameInternal(struct binkMovie* aMovie, AVPacket* aPacket)
|
|||
aMovie->alInited=TRUE;
|
||||
}
|
||||
|
||||
|
||||
memset(aMovie->audioTempBuffer, 0, aMovie->alNumChannels * aMovie->audioFrame->nb_samples * 2 * 2);
|
||||
|
||||
if(aMovie->alNumChannels==0)
|
||||
|
@ -393,71 +327,147 @@ int BinkDecodeFrameInternal(struct binkMovie* aMovie, AVPacket* aPacket)
|
|||
aMovie->alNumFreeBuffers--;
|
||||
aMovie->alFreeBuffers[aMovie->alNumFreeBuffers] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ReadFrame(struct binkMovie* aMovie)
|
||||
{
|
||||
// Read from file if no packet is buffered.
|
||||
if (!aMovie->packet.buf && av_read_frame(aMovie->avContext, &aMovie->packet) < 0) {
|
||||
if (aMovie->looping) {
|
||||
av_seek_frame(aMovie->avContext, -1, 0, 0);
|
||||
return ReadFrame(aMovie);
|
||||
} else {
|
||||
// Drain buffered frames.
|
||||
if (aMovie->videoStreamIndex >= 0)
|
||||
avcodec_send_packet(aMovie->videoCodecContext, NULL);
|
||||
if (aMovie->audioStreamIndex >= 0)
|
||||
avcodec_send_packet(aMovie->audioCodecContext, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Send the (possibly buffered) packet to decoder.
|
||||
int ret = 0;
|
||||
if (aMovie->packet.stream_index == aMovie->videoStreamIndex)
|
||||
ret = avcodec_send_packet(aMovie->videoCodecContext, &aMovie->packet);
|
||||
else if (aMovie->packet.stream_index == aMovie->audioStreamIndex)
|
||||
ret = avcodec_send_packet(aMovie->audioCodecContext, &aMovie->packet);
|
||||
|
||||
// Keep the packet around for next time if decoder’s buffer is full.
|
||||
if (ret == AVERROR(EAGAIN)) {
|
||||
return 1;
|
||||
} else {
|
||||
av_packet_unref(&aMovie->packet);
|
||||
return ret < 0 ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int BinkStartMovie(struct binkMovie* aMovie, const char* aFilename, BOOL aLoopFlag, BOOL aFmvFlag, BOOL aMusicFlag)
|
||||
{
|
||||
BinkInitMovieStruct(aMovie);
|
||||
aMovie->looping = aLoopFlag;
|
||||
|
||||
if(aFmvFlag)
|
||||
{
|
||||
aMovie->videoScaleWidth = 128;
|
||||
aMovie->videoScaleHeight = 96;
|
||||
aMovie->videoScaleFormat = AV_PIX_FMT_RGB24;
|
||||
}
|
||||
|
||||
if(avformat_open_input(&aMovie->avContext, aFilename, NULL, NULL) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!avformat_find_stream_info(aMovie->avContext, NULL) < 0)
|
||||
{
|
||||
BinkReleaseMovie(aMovie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int numStreams = 0;
|
||||
for(int i=0; i<aMovie->avContext->nb_streams; i++)
|
||||
{
|
||||
const AVStream* stream = aMovie->avContext->streams[i];
|
||||
const AVCodec* codec = avcodec_find_decoder(stream->codecpar->codec_id);
|
||||
if (!codec)
|
||||
continue;
|
||||
AVCodecContext *context = avcodec_alloc_context3(codec);
|
||||
if (!context)
|
||||
continue;
|
||||
if (avcodec_parameters_to_context(context, stream->codecpar) < 0 ||
|
||||
avcodec_open2(context, codec, NULL) < 0) {
|
||||
avcodec_free_context(&context);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aMovie->videoStreamIndex < 0 && context->codec_type == AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
aMovie->videoCodecContext = context;
|
||||
aMovie->videoStreamIndex = i;
|
||||
aMovie->videoFrame = av_frame_alloc();
|
||||
aMovie->videoFrameDuration =
|
||||
1000.0f * (float)stream->time_base.num / (float)stream->time_base.den;
|
||||
numStreams++;
|
||||
}
|
||||
else if (aMovie->audioStreamIndex < 0 && context->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
aMovie->audioCodecContext = context;
|
||||
aMovie->audioStreamIndex = i;
|
||||
aMovie->audioFrame = av_frame_alloc();
|
||||
numStreams++;
|
||||
}
|
||||
else
|
||||
{
|
||||
avcodec_free_context(&context);
|
||||
}
|
||||
}
|
||||
|
||||
if(aMovie->videoStreamIndex < 0 && aMovie->audioStreamIndex < 0)
|
||||
{
|
||||
BinkReleaseMovie(aMovie);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!aFmvFlag)
|
||||
{
|
||||
for(int i=0; i<(FRAMEQUEUESIZE-1) * numStreams; i++)
|
||||
ReadFrame(aMovie);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int BinkDecodeFrame(struct binkMovie* aMovie)
|
||||
{
|
||||
AVPacket packet;
|
||||
av_init_packet(&packet);
|
||||
|
||||
if(av_read_frame(aMovie->avContext, &packet) < 0)
|
||||
{
|
||||
if(!aMovie->looping)
|
||||
return 0;
|
||||
|
||||
av_seek_frame(aMovie->avContext, -1, 0, 0);
|
||||
if(av_read_frame(aMovie->avContext, &packet) < 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int result = BinkDecodeFrameInternal(aMovie, &packet);
|
||||
|
||||
// if(packet.data)
|
||||
// av_free_packet(&packet);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int BinkUpdateMovie(struct binkMovie* aMovie)
|
||||
static int BinkUpdateMovie(struct binkMovie* aMovie)
|
||||
{
|
||||
if(!aMovie->avContext)
|
||||
return 0;
|
||||
|
||||
uint timeNow = SDL_GetTicks();
|
||||
float delta = ((float)(timeNow - aMovie->timeLastUpdate)) / 1000.0f;
|
||||
const int t = SDL_GetTicks();
|
||||
const int eof = !ReadFrame(aMovie);
|
||||
|
||||
int playing = 0;
|
||||
if (aMovie->videoStreamIndex >= 0) {
|
||||
if (aMovie->videoFrame->pts == 0)
|
||||
aMovie->timeStart = t - aMovie->videoFrameDuration;
|
||||
if (t - aMovie->timeStart >= aMovie->videoFrame->pts * aMovie->videoFrameDuration)
|
||||
playing += DecodeVideoFrame(aMovie);
|
||||
}
|
||||
|
||||
if(aMovie->videoStreamIndex >= 0)
|
||||
{
|
||||
if(delta < (1.0f / aMovie->videoFrameRate))
|
||||
{
|
||||
if(aMovie->audioStreamIndex<0 || !SoundSys_IsOn() || aMovie->alNumFreeBuffers==0)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if(aMovie->audioStreamIndex >= 0 && aMovie->alInited)
|
||||
{
|
||||
if (aMovie->audioStreamIndex >= 0) {
|
||||
int processedBuffers = 0;
|
||||
alGetSourcei(aMovie->alSource, AL_BUFFERS_PROCESSED, &processedBuffers);
|
||||
if(aMovie->alNumFreeBuffers<=0 && processedBuffers == 0)
|
||||
return 1;
|
||||
while (!aMovie->alInited || aMovie->alNumFreeBuffers>0 || processedBuffers>0) {
|
||||
if (DecodeAudioFrame(aMovie))
|
||||
playing += 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
int streamsPlaying = 0;
|
||||
if(aMovie->videoStreamIndex >= 0)
|
||||
streamsPlaying += BinkDecodeFrame(aMovie);
|
||||
|
||||
if(aMovie->audioStreamIndex >= 0)
|
||||
streamsPlaying += BinkDecodeFrame(aMovie);
|
||||
|
||||
aMovie->timeLastUpdate = timeNow;
|
||||
return (streamsPlaying > 0) ? 1 : 0;
|
||||
}
|
||||
return !eof || playing;
|
||||
}
|
||||
|
||||
|
||||
|
@ -469,13 +479,13 @@ void PlayBinkedFMV(char *filenamePtr, int volume)
|
|||
{
|
||||
struct binkMovie movie;
|
||||
|
||||
if(BinkStartMovie(&movie, filenamePtr, FALSE, FALSE, FALSE))
|
||||
{
|
||||
if (BinkStartMovie(&movie, filenamePtr, FALSE, FALSE, FALSE)) {
|
||||
alSourcef(movie.alSource, AL_GAIN, PlatVolumeToGain(volume));
|
||||
while(BinkUpdateMovie(&movie))
|
||||
{
|
||||
|
||||
while (BinkUpdateMovie(&movie)) {
|
||||
BinkRenderMovie(&movie);
|
||||
FlipBuffers();
|
||||
SDL_Delay(4); // don’t just burn it
|
||||
}
|
||||
BinkReleaseMovie(&movie);
|
||||
}
|
||||
|
@ -541,7 +551,7 @@ int PlayMusicBink(int volume)
|
|||
alGetSourcei(musicMovie.alSource, AL_BUFFERS_PROCESSED, &processedBuffers);
|
||||
if(processedBuffers + musicMovie.alNumFreeBuffers > 0)
|
||||
{
|
||||
if(!BinkDecodeFrame(&musicMovie))
|
||||
if(!ReadFrame(&musicMovie))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -612,7 +622,7 @@ char* GetBinkFMVImage(FMVHandle aFmvHandle)
|
|||
if(!movie->videoScaleContext)
|
||||
return 0;
|
||||
|
||||
return movie->videoScalePicture.data[0];
|
||||
return movie->videoScalePicture[0];
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue