using System.Runtime.InteropServices; using System.Text; using FFmpeg.AutoGen; using FNZCM2.Abstractions.Models.Metadata; namespace FNZCM2.Abstractions.Utility; //有ChatGPT参与辅助生成 public static class FfMpegReader { static FfMpegReader() { ffmpeg.RootPath = "./libFFMPEG/bin"; } public static unsafe FfMpegReadResult? Read(string filePath, out string? err) { // 创建 AVFormatContext 对象 var formatContext = ffmpeg.avformat_alloc_context(); try { var avFormatOpenInputRet = ffmpeg.avformat_open_input(&formatContext, filePath, null, null); if (avFormatOpenInputRet != 0) { var buf = stackalloc byte[512]; ffmpeg.av_strerror(avFormatOpenInputRet, buf, 512); var str = Encoding.ASCII.GetString(buf, 512).TrimEnd('\0'); err = "open:" + str; return null; } // 读取流信息 if (ffmpeg.avformat_find_stream_info(formatContext, null) != 0) { var buf = stackalloc byte[512]; ffmpeg.av_strerror(avFormatOpenInputRet, buf, 512); var str = Encoding.ASCII.GetString(buf, 512).TrimEnd('\0'); err = "find stream:" + str; return null; } int? durMs = formatContext->duration > 0 ? (int)(formatContext->duration / 1000) : null; int? bitRate = formatContext->bit_rate > 0 ? (int)formatContext->bit_rate : null; // 初始化流列表 List streams = new(); // 遍历流信息 for (var i = 0; i < formatContext->nb_streams; i++) { var stream = formatContext->streams[i]; var codecParams = stream->codecpar; var codecType = codecParams->codec_type; // 准备局部变量 var type = codecType; var codec = codecParams->codec_id; AudioInfo? audioInfo = null; PictureInfo? pictureInfo = null; // 处理音频流 if (codecType == AVMediaType.AVMEDIA_TYPE_AUDIO) { var sampleFormat = (AVSampleFormat)codecParams->format; int? bitPerSample = codecParams->bits_per_raw_sample; int? sampleRate = codecParams->sample_rate; bitPerSample = bitPerSample <= 0 ? null : bitPerSample; sampleRate = sampleRate <= 0 ? null : sampleRate; audioInfo = new AudioInfo { SampleFormat = sampleFormat, SampleRate = sampleRate, BitPerSample = bitPerSample }; } // 处理视频流 else if (codecType == AVMediaType.AVMEDIA_TYPE_VIDEO) { var width = codecParams->width; var height = codecParams->height; var pixelFormat = (AVPixelFormat)codecParams->format; pictureInfo = new PictureInfo { Width = width, Height = height, PixelFormat = pixelFormat, }; } //其他流就不管 xxxInfo了 // 初始化 MediaStream 并加入列表 var mediaStream = new FfMpegReadResult.MediaStream { Type = type, Codec = codec, AudioInfo = audioInfo, PictureInfo = pictureInfo }; streams.Add(mediaStream); } // 读取元数据 Dictionary metaData = new(); AVDictionaryEntry* tag = null; while ((tag = ffmpeg.av_dict_get(formatContext->metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null) { var key = Marshal.PtrToStringUTF8((IntPtr)tag->key)!.ToLowerInvariant(); var value = Marshal.PtrToStringUTF8((IntPtr)tag->value)!; metaData[key] = value; } // 构造最终的 FileMetaEntry var fileMetaEntry = new FfMpegReadResult { MetaData = metaData, BitRate = bitRate, DurationMs = durMs, Streams = streams.ToArray(), }; err = null; return fileMetaEntry; } finally { // 释放资源 ffmpeg.avformat_close_input(&formatContext); } } }