From 8875d0226f0d38a1e5ef946e56cd15810627f5ac Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Wed, 3 Aug 2022 16:57:07 -0400 Subject: caching introduced --- ffmpeg_backend.cpp | 169 +++++++++++++++++++++++++++++------------------------ 1 file changed, 93 insertions(+), 76 deletions(-) (limited to 'ffmpeg_backend.cpp') diff --git a/ffmpeg_backend.cpp b/ffmpeg_backend.cpp index e97b4da..dfc1241 100644 --- a/ffmpeg_backend.cpp +++ b/ffmpeg_backend.cpp @@ -19,20 +19,20 @@ av_always_inline std::string av_err2string(int errnum) { #include "ffmpeg_backend.h" -bool32 AV_TryFrame(av_codec_info *AV, av_packet_info *AVLayer, int32 *err) +bool32 AV_TryFrame(av_info *AV, int32 *err) { - *err = av_read_frame(AV->FileFormatContext, AVLayer->VideoPacket); - if (*err >= 0 && AVLayer->VideoPacket->stream_index != AV->VideoStream->index) { - av_packet_unref(AVLayer->VideoPacket); + *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, AVLayer->VideoPacket); + *err = avcodec_send_packet(AV->VideoCodecContext, AV->VideoPacket); else { - *err = avcodec_send_packet(AV->VideoCodecContext, AVLayer->VideoPacket); + *err = avcodec_send_packet(AV->VideoCodecContext, AV->VideoPacket); } - av_packet_unref(AVLayer->VideoPacket); + av_packet_unref(AV->VideoPacket); if (*err < 0) { @@ -41,7 +41,7 @@ bool32 AV_TryFrame(av_codec_info *AV, av_packet_info *AVLayer, int32 *err) } while (*err >= 0) { - *err = avcodec_receive_frame(AV->VideoCodecContext, AVLayer->VideoFrame); + *err = avcodec_receive_frame(AV->VideoCodecContext, AV->VideoFrame); if (*err == AVERROR_EOF) { } else if (*err == AVERROR(EAGAIN)) { *err = 0; @@ -54,6 +54,8 @@ bool32 AV_TryFrame(av_codec_info *AV, av_packet_info *AVLayer, int32 *err) return 0; } +// TODO(fox): Could be combined into AV_Init once we have dealloc functions for +// the AVInfo allocation. bool32 AV_IsFileSupported(char *filename) { int32 err = 0; @@ -84,10 +86,10 @@ bool32 AV_IsFileSupported(char *filename) return 1; } -void AV_CodecInfo_Init(char *filename, source *Source, memory *Memory) +void AV_Init(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory) { - Source->Info.AVCodecInfo = AllocateMemory(Memory, sizeof(av_codec_info), P_AVInfo); - av_codec_info *AV = (av_codec_info *)Source->Info.AVCodecInfo; + BitmapInfo->AVInfo = AllocateMemory(Memory, sizeof(av_info), P_AVInfo); + av_info *AV = (av_info *)BitmapInfo->AVInfo; *AV = {}; int32 err = 0; @@ -96,17 +98,20 @@ void AV_CodecInfo_Init(char *filename, source *Source, memory *Memory) // while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) // printf("%s\n", av_hwdevice_get_type_name(type)); - AV->FileFormatContext = avformat_alloc_context(); - err = avformat_open_input(&AV->FileFormatContext, filename, NULL, NULL);; + // The two calls below theoretically shouldn't fail since we already tested them in IsFileSupported. + AV->FileFormatContext = avformat_alloc_context(); + err = avformat_open_input(&AV->FileFormatContext, Source->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 (int i = 0; i < AV->FileFormatContext->nb_streams; i++) @@ -154,12 +159,20 @@ void AV_CodecInfo_Init(char *filename, source *Source, memory *Memory) 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->Info.FPS = (real32)AV->VideoStream->r_frame_rate.num / AV->VideoStream->r_frame_rate.den; Source->Info.Width = AV->VideoCodecContext->width; Source->Info.Height = AV->VideoCodecContext->height; @@ -167,7 +180,7 @@ void AV_CodecInfo_Init(char *filename, source *Source, memory *Memory) -void AV_GetPTSAverage(av_codec_info *AV, av_packet_info *AVLayer, int32 *err) +void AV_GetPTSAverage(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. @@ -180,62 +193,34 @@ void AV_GetPTSAverage(av_codec_info *AV, av_packet_info *AVLayer, int32 *err) int16 i = 0; real32 AvgPTSPerSecond = 0; for (;;) { - if (AV_TryFrame(AV, AVLayer, err)) { + if (AV_TryFrame(AV, err)) { if (i >= FPS * TestAmount) { - AvgPTSPerSecond = (real32)AVLayer->VideoFrame->pts / TestAmount; - printf("frame: %i, pts: %li\n", i, AVLayer->VideoFrame->pts); + AvgPTSPerSecond = (real32)AV->VideoFrame->pts / TestAmount; + printf("frame: %i, pts: %li\n", i, AV->VideoFrame->pts); break; } i++; - av_frame_unref(AVLayer->VideoFrame); + av_frame_unref(AV->VideoFrame); } } - AV->AvgPTSPerFrame = (real32)AvgPTSPerSecond / (int32)(FPS + 0.5f); - printf("Avg PTS per sec: %.06f, Avg PTS per frame: %.06f\n", AvgPTSPerSecond, AV->AvgPTSPerFrame); + Source->Info.AvgPTSPerFrame = (real32)AvgPTSPerSecond / (int32)(FPS + 0.5f); + printf("Avg PTS per sec: %.06f, Avg PTS per frame: %.06f\n", AvgPTSPerSecond, Source->Info.AvgPTSPerFrame); av_seek_frame(AV->FileFormatContext, -1, 0, AVSEEK_FLAG_BACKWARD); } - -void AV_PacketInfo_Init(layer_bitmap_info *BitmapInfo, memory *Memory) -{ - BitmapInfo->AVPacketInfo = AllocateMemory(Memory, sizeof(av_packet_info), P_AVInfo); - av_packet_info *AV = (av_packet_info *)BitmapInfo->AVPacketInfo; - *AV = {}; - printf("%li", AV->PreviousPTS); - - int32 err = 0; - - 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)); - } -} - - -static void -Convert4x4Chunk(pixel_buffer *Raster, uint8); -static void -ClearBuffer(pixel_buffer *Raster, void *); - bool32 AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo, memory *Memory, int32 TimelineFrame) { - av_codec_info *AV = (av_codec_info *)Source->Info.AVCodecInfo; - av_packet_info *AVLayer = (av_packet_info *)BitmapInfo->AVPacketInfo; - + av_info *AV = (av_info *)BitmapInfo->AVInfo; int32 *CurrentlyRenderedFrame = &BitmapInfo->CurrentFrame; int32 err = 0; - if (!AV->AvgPTSPerFrame) { - AV_GetPTSAverage(AV, AVLayer, &err); + if (!Source->Info.AvgPTSPerFrame) { + AV_GetPTSAverage(Source, AV, &err); } - Assert(AV->AvgPTSPerFrame); + Assert(Source->Info.AvgPTSPerFrame); int p = 0; int i = 0; @@ -258,28 +243,28 @@ bool32 AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo, memory * *CurrentlyRenderedFrame = FrameToSeek; - int64 SeekPTS = (int64)(AV->AvgPTSPerFrame*FrameToSeek + 0.5f); + int64 SeekPTS = (int64)(Source->Info.AvgPTSPerFrame*FrameToSeek + 0.5f); while (err >= 0) { - if (AV_TryFrame(AV, AVLayer, &err)) { + 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 && AVLayer->VideoFrame->pts != AV->VideoStream->start_time) { - av_frame_unref(AVLayer->VideoFrame); - printf("NON-START: avg: %li, real pts: %li", SeekPTS, AVLayer->VideoFrame->pts); + 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 = AVLayer->VideoFrame->pts - SeekPTS; - if (abs(Difference) < AV->AvgPTSPerFrame) + int64 Difference = AV->VideoFrame->pts - SeekPTS; + if (abs(Difference) < Source->Info.AvgPTSPerFrame) { - if (AVLayer->PreviousPTS == -1) { - AVLayer->PreviousPTS = AVLayer->VideoFrame->pts; - printf("avg: %li, real pts: %li, difference: %li\n", SeekPTS, AVLayer->VideoFrame->pts, Difference); + 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, AVLayer->VideoFrame->pts, AVLayer->VideoFrame->pts - SeekPTS, AVLayer->VideoFrame->pts - AVLayer->PreviousPTS); - AVLayer->PreviousPTS = AVLayer->VideoFrame->pts; + 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->Info.Width; @@ -287,31 +272,63 @@ bool32 AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo, memory * uint16 BytesPerPixel = Source->Info.BytesPerPixel; int32 Pitch = Width*BytesPerPixel; - void *Buffer = AllocateMemory(Memory, Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel), B_LoadedBitmaps); + // probably should rename this + memory_table *Table = &Memory->Slot[B_LoadedBitmaps]; + uint64 Size = Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel); + if (Table->CurrentPosition + Size > Table->Size) { + Table->CurrentPosition = 0; + Table->PointerIndex = 0; + } + cached_bitmap *Bitmap = &Memory->Bitmap[Table->PointerIndex]; + if (Table->PointerIndex < Table->NumberOfPointers) { + bool32 Avail = false; + void *DataStart = Memory->Bitmap[Table->PointerIndex].Data; + while(!Avail) { + void *Data2 = Memory->Bitmap[Table->PointerIndex+1].Data; + uint64 BytesBetween = (uint8 *)Data2 - (uint8 *)DataStart; + if (BytesBetween < Size) { + Memory->Bitmap[Table->PointerIndex+1].SourceOwner = NULL; + Table->PointerIndex++; + } else { + Avail = true; + } + Table->NumberOfPointers--; + } + } + Table->NumberOfPointers++; + Bitmap->Data = AllocateMemory(Memory, Size, B_LoadedBitmaps); + if (!Bitmap->Data) { + Assert(0); + } + Bitmap->SourceOwner = Source; + Bitmap->Frame = FrameToSeek; + Bitmap->Index = Table->PointerIndex; + Table->PointerIndex++; + 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. - AVLayer->RGBContext = sws_getContext(AVLayer->VideoFrame->width, AVLayer->VideoFrame->height, (AVPixelFormat)AVLayer->VideoFrame->format, - AVLayer->VideoFrame->width, AVLayer->VideoFrame->height, AV_PIX_FMT_RGBA, SWS_BILINEAR, + 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(!AVLayer->RGBContext) { + if(!AV->RGBContext) { printf("Libav error: SwsContext creation failed."); } - sws_scale(AVLayer->RGBContext, AVLayer->VideoFrame->data, AVLayer->VideoFrame->linesize, 0, AVLayer->VideoFrame->height, + sws_scale(AV->RGBContext, AV->VideoFrame->data, AV->VideoFrame->linesize, 0, AV->VideoFrame->height, dst_data, out_linesize); - av_frame_unref(AVLayer->VideoFrame); + av_frame_unref(AV->VideoFrame); - if (!BitmapInfo->BitmapBuffer) { - BitmapInfo->BitmapBuffer = AllocateMemory(Memory, Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel), B_LayerBitmaps); - } + Assert(BitmapInfo->BitmapBuffer); void *DestBuffer = BitmapInfo->BitmapBuffer; Bitmap_ConvertPacking(Buffer, DestBuffer, Width, Height, BytesPerPixel, 0); + // void *Buffer2 = AllocateMemory(Memory, Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel), B_LoadedBitmaps); + // uint64 test = &Buffer2 - &Buffer; // CopyToBuffer(Buffer, 1); // Bitmap_Clear(Buffer, Source->Info.Width, Source->Info.Height, Source->Info.BytesPerPixel); @@ -320,9 +337,9 @@ bool32 AV_LoadVideoFrame(source *Source, layer_bitmap_info *BitmapInfo, memory * 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, AVLayer->VideoFrame->pts, Difference); + printf("FRAME SKIP: avg: %li, real pts: %li, difference: %li\n", SeekPTS, AV->VideoFrame->pts, Difference); } - av_frame_unref(AVLayer->VideoFrame); + av_frame_unref(AV->VideoFrame); } } /* -- cgit v1.2.3