123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- 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<FfMpegReadResult.MediaStream> 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<string, string> 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);
- }
- }
- }
|