FfMpegReader.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using System.Runtime.InteropServices;
  2. using System.Text;
  3. using FFmpeg.AutoGen;
  4. using FNZCM2.Abstractions.Models.Metadata;
  5. namespace FNZCM2.Abstractions.Utility;
  6. //有ChatGPT参与辅助生成
  7. public static class FfMpegReader
  8. {
  9. static FfMpegReader()
  10. {
  11. ffmpeg.RootPath = "./libFFMPEG/bin";
  12. }
  13. public static unsafe FfMpegReadResult? Read(string filePath, out string? err)
  14. {
  15. // 创建 AVFormatContext 对象
  16. var formatContext = ffmpeg.avformat_alloc_context();
  17. try
  18. {
  19. var avFormatOpenInputRet = ffmpeg.avformat_open_input(&formatContext, filePath, null, null);
  20. if (avFormatOpenInputRet != 0)
  21. {
  22. var buf = stackalloc byte[512];
  23. ffmpeg.av_strerror(avFormatOpenInputRet, buf, 512);
  24. var str = Encoding.ASCII.GetString(buf, 512).TrimEnd('\0');
  25. err = "open:" + str;
  26. return null;
  27. }
  28. // 读取流信息
  29. if (ffmpeg.avformat_find_stream_info(formatContext, null) != 0)
  30. {
  31. var buf = stackalloc byte[512];
  32. ffmpeg.av_strerror(avFormatOpenInputRet, buf, 512);
  33. var str = Encoding.ASCII.GetString(buf, 512).TrimEnd('\0');
  34. err = "find stream:" + str;
  35. return null;
  36. }
  37. int? durMs = formatContext->duration > 0 ? (int)(formatContext->duration / 1000) : null;
  38. int? bitRate = formatContext->bit_rate > 0 ? (int)formatContext->bit_rate : null;
  39. // 初始化流列表
  40. List<FfMpegReadResult.MediaStream> streams = new();
  41. // 遍历流信息
  42. for (var i = 0; i < formatContext->nb_streams; i++)
  43. {
  44. var stream = formatContext->streams[i];
  45. var codecParams = stream->codecpar;
  46. var codecType = codecParams->codec_type;
  47. // 准备局部变量
  48. var type = codecType;
  49. var codec = codecParams->codec_id;
  50. AudioInfo? audioInfo = null;
  51. PictureInfo? pictureInfo = null;
  52. // 处理音频流
  53. if (codecType == AVMediaType.AVMEDIA_TYPE_AUDIO)
  54. {
  55. var sampleFormat = (AVSampleFormat)codecParams->format;
  56. int? bitPerSample = codecParams->bits_per_raw_sample;
  57. int? sampleRate = codecParams->sample_rate;
  58. bitPerSample = bitPerSample <= 0 ? null : bitPerSample;
  59. sampleRate = sampleRate <= 0 ? null : sampleRate;
  60. audioInfo = new AudioInfo
  61. {
  62. SampleFormat = sampleFormat,
  63. SampleRate = sampleRate,
  64. BitPerSample = bitPerSample
  65. };
  66. }
  67. // 处理视频流
  68. else if (codecType == AVMediaType.AVMEDIA_TYPE_VIDEO)
  69. {
  70. var width = codecParams->width;
  71. var height = codecParams->height;
  72. var pixelFormat = (AVPixelFormat)codecParams->format;
  73. pictureInfo = new PictureInfo
  74. {
  75. Width = width,
  76. Height = height,
  77. PixelFormat = pixelFormat,
  78. };
  79. }
  80. //其他流就不管 xxxInfo了
  81. // 初始化 MediaStream 并加入列表
  82. var mediaStream = new FfMpegReadResult.MediaStream
  83. {
  84. Type = type,
  85. Codec = codec,
  86. AudioInfo = audioInfo,
  87. PictureInfo = pictureInfo
  88. };
  89. streams.Add(mediaStream);
  90. }
  91. // 读取元数据
  92. Dictionary<string, string> metaData = new();
  93. AVDictionaryEntry* tag = null;
  94. while ((tag = ffmpeg.av_dict_get(formatContext->metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null)
  95. {
  96. var key = Marshal.PtrToStringUTF8((IntPtr)tag->key)!.ToLowerInvariant();
  97. var value = Marshal.PtrToStringUTF8((IntPtr)tag->value)!;
  98. metaData[key] = value;
  99. }
  100. // 构造最终的 FileMetaEntry
  101. var fileMetaEntry = new FfMpegReadResult
  102. {
  103. MetaData = metaData,
  104. BitRate = bitRate,
  105. DurationMs = durMs,
  106. Streams = streams.ToArray(),
  107. };
  108. err = null;
  109. return fileMetaEntry;
  110. }
  111. finally
  112. {
  113. // 释放资源
  114. ffmpeg.avformat_close_input(&formatContext);
  115. }
  116. }
  117. }