public Surface(int width, int height) { RequestedWidth = width; RequestedHeight = height; Frame = FFmpegApi.av_frame_alloc(); }
static FFmpegContext() { _logFunc = Log; // Redirect log output. FFmpegApi.av_log_set_level(AVLog.MaxOffset); FFmpegApi.av_log_set_callback(_logFunc); }
public FFmpegContext(AVCodecID codecId) { _codec = FFmpegApi.avcodec_find_decoder(codecId); if (_codec == null) { Logger.Error?.PrintMsg(LogClass.FFmpeg, $"Codec wasn't found. Make sure you have the {codecId} codec present in your FFmpeg installation."); return; } _context = FFmpegApi.avcodec_alloc_context3(_codec); if (_context == null) { Logger.Error?.PrintMsg(LogClass.FFmpeg, "Codec context couldn't be allocated."); return; } if (FFmpegApi.avcodec_open2(_context, _codec, null) != 0) { Logger.Error?.PrintMsg(LogClass.FFmpeg, "Codec couldn't be opened."); return; } _packet = FFmpegApi.av_packet_alloc(); if (_packet == null) { Logger.Error?.PrintMsg(LogClass.FFmpeg, "Packet couldn't be allocated."); return; } int avCodecRawVersion = FFmpegApi.avcodec_version(); int avCodecMajorVersion = avCodecRawVersion >> 16; int avCodecMinorVersion = (avCodecRawVersion >> 8) & 0xFF; // libavcodec 59.24 changed AvCodec to move its private API and also move the codec function to an union. if (avCodecMajorVersion > 59 || (avCodecMajorVersion == 59 && avCodecMinorVersion > 24)) { _decodeFrame = Marshal.GetDelegateForFunctionPointer <FFCodec.AVCodec_decode>(((FFCodec *)_codec)->CodecCallback); } // libavcodec 59.x changed AvCodec private API layout. else if (avCodecMajorVersion == 59) { _decodeFrame = Marshal.GetDelegateForFunctionPointer <FFCodec.AVCodec_decode>(((FFCodecLegacy <AVCodec> *)_codec)->Decode); } // libavcodec 58.x and lower else { _decodeFrame = Marshal.GetDelegateForFunctionPointer <FFCodec.AVCodec_decode>(((FFCodecLegacy <AVCodecLegacy> *)_codec)->Decode); } }
public void Dispose() { fixed(AVPacket **ppPacket = &_packet) { FFmpegApi.av_packet_free(ppPacket); } FFmpegApi.avcodec_close(_context); fixed(AVCodecContext **ppContext = &_context) { FFmpegApi.avcodec_free_context(ppContext); } }
private static void Log(void *ptr, AVLog level, string format, byte *vl) { if (level > FFmpegApi.av_log_get_level()) { return; } int lineSize = 1024; byte *lineBuffer = stackalloc byte[lineSize]; int printPrefix = 1; FFmpegApi.av_log_format_line(ptr, level, format, vl, lineBuffer, lineSize, &printPrefix); string line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer).Trim(); switch (level) { case AVLog.Panic: case AVLog.Fatal: case AVLog.Error: Logger.Error?.Print(LogClass.FFmpeg, line); break; case AVLog.Warning: Logger.Warning?.Print(LogClass.FFmpeg, line); break; case AVLog.Info: Logger.Info?.Print(LogClass.FFmpeg, line); break; case AVLog.Verbose: case AVLog.Debug: Logger.Debug?.Print(LogClass.FFmpeg, line); break; case AVLog.Trace: Logger.Trace?.Print(LogClass.FFmpeg, line); break; } }
public int DecodeFrame(Surface output, ReadOnlySpan <byte> bitstream) { FFmpegApi.av_frame_unref(output.Frame); int result; int gotFrame; fixed(byte *ptr = bitstream) { _packet->Data = ptr; _packet->Size = bitstream.Length; result = _decodeFrame(_context, output.Frame, &gotFrame, _packet); } if (gotFrame == 0) { FFmpegApi.av_frame_unref(output.Frame); // If the frame was not delivered, it was probably delayed. // Get the next delayed frame by passing a 0 length packet. _packet->Data = null; _packet->Size = 0; result = _decodeFrame(_context, output.Frame, &gotFrame, _packet); // We need to set B frames to 0 as we already consumed all delayed frames. // This prevents the decoder from trying to return a delayed frame next time. _context->HasBFrames = 0; } FFmpegApi.av_packet_unref(_packet); if (gotFrame == 0) { FFmpegApi.av_frame_unref(output.Frame); return(-1); } return(result < 0 ? result : 0); }
public void Dispose() { FFmpegApi.av_frame_unref(Frame); FFmpegApi.av_free(Frame); }