-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathQsvDecode.cs
More file actions
112 lines (100 loc) · 4.91 KB
/
Copy pathQsvDecode.cs
File metadata and controls
112 lines (100 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
using System;
using System.IO;
using FFmpeg.AutoGen;
namespace FFmpeg.Sharp.Example
{
/// <summary>
/// Maps to FFmpeg example: qsv_decode.c
/// Intel QSV-accelerated H.264 decoding: output frames are held in GPU video surfaces,
/// then transferred to system memory and written raw to an output file.
/// Usage: args[0] = input.h264/mp4, args[1] = output.raw
/// </summary>
public class QsvDecode : ExampleBase
{
public QsvDecode() { Index = 21; Enable = false; }
public override void Execute()
{
var inFile = args.Length > 0 ? args[0] : "input.mp4";
var outFile = args.Length > 1 ? args[1] : "out_qsv.raw";
// ── Open input ────────────────────────────────────────────────────
using var demuxer = MediaDemuxer.Open(inFile);
// Find the first H.264 video stream; discard all others.
int videoStreamIdx = -1;
for (int i = 0; i < (int)demuxer.Ref.nb_streams; i++)
{
if (demuxer[i].CodecparRef.codec_id == AVCodecID.AV_CODEC_ID_H264 && videoStreamIdx < 0)
videoStreamIdx = i;
else
demuxer[i].Ref.discard = AVDiscard.AVDISCARD_ALL;
}
if (videoStreamIdx < 0)
throw new Exception("No H.264 video stream found in the input file");
// ── Decoder ───────────────────────────────────────────────────────
var qsvDecoder = MediaCodec.FindDecoder("h264_qsv")
?? throw new Exception("The QSV decoder (h264_qsv) is not present in libavcodec");
// InitHWDeviceContext creates the QSV device (an "auto" session) and wires the
// get_format callback that always picks AV_PIX_FMT_QSV.
using var decoder = new MediaDecoder(qsvDecoder);
decoder.SetCodecParameters(ref demuxer[videoStreamIdx].CodecparRef);
if (decoder.InitHWDeviceContext(AVHWDeviceType.AV_HWDEVICE_TYPE_QSV, "auto") == 0)
throw new Exception("The QSV pixel format not offered by the decoder's HW configs");
decoder.Open();
// ── Output ────────────────────────────────────────────────────────
using var output = MediaIOContext.Open(outFile, ffmpeg.AVIO_FLAG_WRITE);
using var frame = new MediaFrame();
using var swFrame = new MediaFrame();
using var packet = new MediaPacket();
// ── Decode loop ───────────────────────────────────────────────────
int ret = 0;
foreach (var pkt in demuxer.ReadPackets(packet))
{
if (pkt.Ref.stream_index != videoStreamIdx) continue;
ret = DecodePacket(decoder, frame, swFrame, pkt, output);
if (ret < 0) break;
}
// Flush decoder.
DecodePacket(decoder, frame, swFrame, null, output);
}
private static int DecodePacket(MediaDecoder decoder, MediaFrame frame, MediaFrame swFrame,
MediaPacket pkt, MediaIOContext output)
{
int ret = decoder.SendPacket(pkt);
if (ret < 0)
{
Console.Error.WriteLine("Error during decoding");
return ret;
}
while (ret >= 0)
{
ret = decoder.ReceiveFrame(frame);
if (ret == ffmpeg.AVERROR(ffmpeg.EAGAIN) || ret == ffmpeg.AVERROR_EOF)
break;
if (ret < 0)
{
Console.Error.WriteLine("Error during decoding");
return ret;
}
// Transfer GPU frame → system memory, then write the raw frame
// (planes tightly packed, padding stripped) to the output file.
swFrame.Unref();
try
{
MediaCodecContext.HWFrameTransferData(swFrame, frame);
output.Write(swFrame.GetBytes(padding: false));
}
catch (FFmpegException e)
{
Console.Error.WriteLine("Error transferring the data to system memory");
ret = e.ErrorCode;
}
finally
{
swFrame.Unref();
frame.Unref();
}
if (ret < 0) return ret;
}
return 0;
}
}
}