summaryrefslogtreecommitdiff
path: root/ffmpeg_backend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg_backend.cpp')
-rw-r--r--ffmpeg_backend.cpp386
1 files changed, 0 insertions, 386 deletions
diff --git a/ffmpeg_backend.cpp b/ffmpeg_backend.cpp
deleted file mode 100644
index a54fb51..0000000
--- a/ffmpeg_backend.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-extern "C" {
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include <libavformat/avio.h>
-#include <libavutil/avutil.h>
-#include <libswscale/swscale.h>
-}
-
-// workaround to make libav error printing work
-#ifdef av_err2str
-#undef av_err2str
-#include <string>
-av_always_inline std::string av_err2string(int errnum) {
- char str[AV_ERROR_MAX_STRING_SIZE];
- return av_make_error_string(str, AV_ERROR_MAX_STRING_SIZE, errnum);
-}
-#define av_err2str(err) av_err2string(err).c_str()
-#endif // av_err2str
-
-#include "ffmpeg_backend.h"
-
-bool32 AV_TryFrame(av_info *AV, int32 *err)
-{
- *err = av_read_frame(AV->FileFormatContext, AV->VideoPacket);
- if (*err >= 0 && AV->VideoPacket->stream_index != AV->VideoStream->index) {
- av_packet_unref(AV->VideoPacket);
- return 0;
- }
-
- if (*err < 0)
- *err = avcodec_send_packet(AV->VideoCodecContext, AV->VideoPacket);
- else {
- *err = avcodec_send_packet(AV->VideoCodecContext, AV->VideoPacket);
- }
- av_packet_unref(AV->VideoPacket);
-
- if (*err < 0)
- {
- fprintf(stderr, "Libav *error: (%s)\n", av_err2str(*err));
- Assert(0);
- }
-
- while (*err >= 0) {
- *err = avcodec_receive_frame(AV->VideoCodecContext, AV->VideoFrame);
- if (*err == AVERROR_EOF) {
- av_seek_frame(AV->FileFormatContext, -1, 0, AVSEEK_FLAG_BACKWARD);
- *err = 0;
- break;
- } else if (*err == AVERROR(EAGAIN)) {
- *err = 0;
- break;
- } else if (*err < 0) {
- Assert(0);
- }
- return 1;
- }
- return 0;
-}
-
-bool32 AV_IsFileSupported(char *filename, bool32 *IsVideo)
-{
- int32 err = 0;
-
- // enum AVHWDeviceType type;
- // while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
- // printf("%s\n", av_hwdevice_get_type_name(type));
-
- AVFormatContext *temp = avformat_alloc_context();
- err = avformat_open_input(&temp, filename, NULL, NULL);;
-
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- avformat_free_context(temp);
- return 0;
- }
-
- err = avformat_find_stream_info(temp, NULL);
-
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- avformat_free_context(temp);
- return 0;
- }
-
- for (uint32 i = 0; i < temp->nb_streams; i++)
- {
- AVCodecParameters *LocalCodecParameters = NULL;
- LocalCodecParameters = temp->streams[i]->codecpar;
- if (LocalCodecParameters->codec_type == AVMEDIA_TYPE_VIDEO) {
- if (temp->streams[i]->duration > 1) {
- *IsVideo = true;
- }
- avformat_free_context(temp);
- return 1;
- }
- }
-
- printf("Libav error: No video track found.");
-
- return 0;
-}
-
-// Note that we can't get away with not having to keep track of the AV pointer
-// for undos by clearing/reallocing these contexts every frame since the state
-// of the PTS value is stored inside FileFormatContext.
-void AV_Dealloc(av_info *AV)
-{
- Assert(AV);
- avformat_free_context(AV->FileFormatContext);
- avcodec_free_context(&AV->VideoCodecContext);
- av_packet_free(&AV->VideoPacket);
- av_frame_free(&AV->VideoFrame);
-};
-
-void AV_Init(block_source *Source, av_info *AV, memory *Memory)
-{
- *AV = {};
-
- int32 err = 0;
-
- // enum AVHWDeviceType type;
- // while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
- // printf("%s\n", av_hwdevice_get_type_name(type));
-
- // The two calls below theoretically shouldn't fail since we already tested them in IsFileSupported.
-
- AV->FileFormatContext = avformat_alloc_context();
- char *Path = (char *)Memory_Block_AddressAtIndex(Memory, F_Strings, Source->Path_String_Index);
- err = avformat_open_input(&AV->FileFormatContext, Path, NULL, NULL);;
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- Assert(0);
- }
-
- err = avformat_find_stream_info(AV->FileFormatContext, NULL);
-
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- Assert(0);
- }
-
- for (uint32 i = 0; i < AV->FileFormatContext->nb_streams; i++)
- {
- AVCodecParameters *LocalCodecParameters = NULL;
- LocalCodecParameters = AV->FileFormatContext->streams[i]->codecpar;
- if (LocalCodecParameters->codec_type == AVMEDIA_TYPE_VIDEO) {
- AV->VideoCodecParameters = LocalCodecParameters;
- AV->VideoStream = AV->FileFormatContext->streams[i];
- break;
- }
- }
-
- if (!AV->VideoCodecParameters) {
- printf("Libav error: No video track found.");
- }
-
- AV->VideoCodec = avcodec_find_decoder(AV->VideoCodecParameters->codec_id);
-
- if (!AV->VideoCodec) {
- printf("Libav error: Suitable decoder could not be identified for codec:\n");
- }
-/*
- int16 codecs = 0;
- for (;;) {
- AV->VideoHWConfig = avcodec_get_hw_config(AV->VideoCodec, codecs);
- if (!AV->VideoHWConfig) {
- printf("Libav error: Hardware acceleration not found for decoder %s.",
- AV->VideoCodec->name);
- break;
- }
- AV->HWPixFormat = AV->VideoHWConfig->pix_fmt;
- break;
- // if (AV->VideoHWConfig->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX &&
- // AV->VideoHWConfig->device_type == type) {
- // }
- codecs++;
- }
-*/
- AV->VideoCodecContext = avcodec_alloc_context3(AV->VideoCodec);
- if (!AV->VideoCodecContext) {
- printf("Libav error: Decoder context allocation failed.");
- }
- err = avcodec_parameters_to_context(AV->VideoCodecContext, AV->VideoCodecParameters);
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- }
- avcodec_open2(AV->VideoCodecContext, AV->VideoCodec, NULL);
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- }
-
- AV->VideoPacket = av_packet_alloc();
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- }
- AV->VideoFrame = av_frame_alloc();
- if (err < 0) {
- fprintf(stderr, "Libav error: (%s)\n", av_err2str(err));
- }
-
- Source->BytesPerPixel = 4;
- Source->FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den;
- Source->Width = AV->VideoCodecContext->width;
- Source->Height = AV->VideoCodecContext->height;
-};
-
-
-
-void AV_GetPTSAverage(block_source *Source, av_info *AV, int32 *err)
-{
- // TODO(fox): This PTS average isn't exact and causes an occasional
- // frame skip. See libav remarks in forum for more details.
-
- if (AV->VideoStream->duration == 1) {
- Source->AvgPTSPerFrame = 1;
- return;
- }
-
- // TODO(fox): Handle footage under five seconds.
- int16 TestAmount = 5;
-
- real32 FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den;
-
- int16 i = 0;
- real32 AvgPTSPerSecond = 0;
- for (;;) {
- if (AV_TryFrame(AV, err)) {
- if (i >= FPS * TestAmount) {
- AvgPTSPerSecond = (real32)AV->VideoFrame->pts / TestAmount;
- printf("frame: %i, pts: %li\n", i, AV->VideoFrame->pts);
- break;
- }
- i++;
- av_frame_unref(AV->VideoFrame);
- }
- }
-
- Source->AvgPTSPerFrame = (real32)AvgPTSPerSecond / (int32)(FPS + 0.5f);
- printf("Avg PTS per sec: %.06f, Avg PTS per frame: %.06f\n", AvgPTSPerSecond, Source->AvgPTSPerFrame);
-
- av_seek_frame(AV->FileFormatContext, -1, 0, AVSEEK_FLAG_BACKWARD);
-}
-
-#if 0
-cached_bitmap * AV_LoadStill(block_source *Source, layer_bitmap_info *BitmapInfo, memory *Memory)
-{
- av_info *AV = (av_info *)BitmapInfo->AVInfo;
- int32 *CurrentlyRenderedFrame = &BitmapInfo->CurrentFrame;
-
- int32 err = 0;
-
- *CurrentlyRenderedFrame = 0;
-
- av_seek_frame(AV->FileFormatContext, -1, 0, AVSEEK_FLAG_FRAME);
-
- while (err >= 0) {
- if (AV_TryFrame(AV, &err))
- {
- uint16 Width = Source->Width;
- uint16 Height = Source->Height;
- uint16 BytesPerPixel = Source->BytesPerPixel;
- int32 Pitch = Width*BytesPerPixel;
-
- cached_bitmap *Bitmap = Memory_RollingBitmap(Memory, Source, 0);
- void *Buffer = Bitmap->Data;
-
- int out_linesize[4] = { Pitch, Pitch, Pitch, Pitch };
- uint8 *dst_data[4] = { (uint8 *)Buffer, (uint8 *)Buffer + Width*Height*BytesPerPixel,
- (uint8 *)Buffer + Width*Height*BytesPerPixel*2, (uint8 *)Buffer + Width*Height*BytesPerPixel*3 };
-
- // NOTE(fox): This function will be replaced in the future.
- AV->RGBContext = sws_getContext(AV->VideoFrame->width, AV->VideoFrame->height, (AVPixelFormat)AV->VideoFrame->format,
- AV->VideoFrame->width, AV->VideoFrame->height, AV_PIX_FMT_RGBA, SWS_BILINEAR,
- NULL, NULL, NULL);
-
- if(!AV->RGBContext) {
- printf("Libav error: SwsContext creation failed.");
- }
-
- sws_scale(AV->RGBContext, AV->VideoFrame->data, AV->VideoFrame->linesize, 0, AV->VideoFrame->height,
- dst_data, out_linesize);
-
- av_frame_unref(AV->VideoFrame);
-
- Assert(BitmapInfo->BitmapBuffer);
- return Bitmap;
- }
- av_frame_unref(AV->VideoFrame);
- }
- return 0;
-}
-
-cached_bitmap * AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, int32 TimelineFrame)
-{
- av_info *AV = (av_info *)BitmapInfo->AVInfo;
- int32 *CurrentlyRenderedFrame = &BitmapInfo->CurrentFrame;
-
- int32 err = 0;
-
- if (!Source->AvgPTSPerFrame) {
- AV_GetPTSAverage(Source, AV, &err);
- }
- Assert(Source->AvgPTSPerFrame);
-
- int32 FrameToSeek = TimelineFrame - BitmapInfo->FrameOffset;
- if (*CurrentlyRenderedFrame == FrameToSeek || FrameToSeek < 0)
- return 0;
-
- // NOTE(fox): The decoder automatically advances to the next frame, so we
- // don't need to call av_seek_frame under normal playback.
- // This function only seeks to the nearest "keyframe."
-
- if (*CurrentlyRenderedFrame != FrameToSeek - 1) {
- int64 SeekSeconds = (int64)(FrameToSeek / (int32)(Source->FPS + 0.5f) * AV_TIME_BASE);
- av_seek_frame(AV->FileFormatContext, -1, SeekSeconds, AVSEEK_FLAG_BACKWARD);
- printf("Seek activated\n");
- } else if (*CurrentlyRenderedFrame < 0) {
- av_seek_frame(AV->FileFormatContext, -1, 0, AVSEEK_FLAG_BACKWARD);
- }
-
- *CurrentlyRenderedFrame = FrameToSeek;
-
- int64 SeekPTS = (int64)(Source->AvgPTSPerFrame*FrameToSeek + 0.5f);
-
- while (err >= 0) {
- if (AV_TryFrame(AV, &err)) {
-
- // The first frame that gets loaded isn't always the actual
- // first frame, so we need to check until it's correct.
- if (FrameToSeek == 0 && AV->VideoFrame->pts != AV->VideoStream->start_time) {
- av_frame_unref(AV->VideoFrame);
- // printf("NON-START: avg: %li, real pts: %li", SeekPTS, AV->VideoFrame->pts);
- continue;
- }
-
- int64 Difference = AV->VideoFrame->pts - SeekPTS;
- if (abs(Difference) < Source->AvgPTSPerFrame)
- {
- if (AV->PreviousPTS == -1) {
- AV->PreviousPTS = AV->VideoFrame->pts;
- // printf("avg: %li, real pts: %li, difference: %li\n", SeekPTS, AV->VideoFrame->pts, Difference);
- } else {
- // printf("avg: %li, real pts: %li, difference: %li difference from last pts: %li\n", SeekPTS, AV->VideoFrame->pts, AV->VideoFrame->pts - SeekPTS, AV->VideoFrame->pts - AV->PreviousPTS);
- AV->PreviousPTS = AV->VideoFrame->pts;
- }
-
- uint16 Width = Source->Width;
- uint16 Height = Source->Height;
- uint16 BytesPerPixel = Source->BytesPerPixel;
- int32 Pitch = Width*BytesPerPixel;
-
- cached_bitmap *Bitmap = Memory_RollingBitmap(Memory, Source, FrameToSeek);
- void *Buffer = Bitmap->Data;
-
- int out_linesize[4] = { Pitch, Pitch, Pitch, Pitch };
- uint8 *dst_data[4] = { (uint8 *)Buffer, (uint8 *)Buffer + Width*Height*BytesPerPixel,
- (uint8 *)Buffer + Width*Height*BytesPerPixel*2, (uint8 *)Buffer + Width*Height*BytesPerPixel*3 };
-
- // NOTE(fox): This function will be replaced in the future.
- AV->RGBContext = sws_getContext(AV->VideoFrame->width, AV->VideoFrame->height, (AVPixelFormat)AV->VideoFrame->format,
- AV->VideoFrame->width, AV->VideoFrame->height, AV_PIX_FMT_RGBA, SWS_BILINEAR,
- NULL, NULL, NULL);
-
- if(!AV->RGBContext) {
- printf("Libav error: SwsContext creation failed.");
- }
-
- sws_scale(AV->RGBContext, AV->VideoFrame->data, AV->VideoFrame->linesize, 0, AV->VideoFrame->height,
- dst_data, out_linesize);
-
- av_frame_unref(AV->VideoFrame);
-
- Assert(BitmapInfo->BitmapBuffer);
- return Bitmap;
- }
- else
- {
- // If this gets printed when not seeking, a frame has been skipped!
- // printf("FRAME SKIP: avg: %li, real pts: %li, difference: %li\n", SeekPTS, AV->VideoFrame->pts, Difference);
- }
- av_frame_unref(AV->VideoFrame);
- }
- }
- return 0;
-}
-#endif