1. Adds hardware_frames_constraints to retrieve valid HWPixelFormats and SWPixelFormats for specific hardware frame configurations. (#151)

2. Implements a HardwareFramesConstraints method in hardware_device_context to obtain these constraints for a given hardware frames context.
This commit is contained in:
Maizer
2025-05-15 20:33:28 +08:00
committed by GitHub
parent 74973f7e03
commit e4be514918
4 changed files with 121 additions and 20 deletions

View File

@@ -102,14 +102,16 @@ func main() {
continue
}
// Merge decoder name with hardware device type name
if *decoderCodecName == "" {
*decoderCodecName = fmt.Sprintf("%s_%s", is.CodecParameters().CodecID().Name(), *hardwareDeviceTypeName)
}
// Update input stream
inputStream = is
// Find decoder
decCodec = astiav.FindDecoder(is.CodecParameters().CodecID())
if *decoderCodecName != "" {
decCodec = astiav.FindDecoderByName(*decoderCodecName)
}
decCodec = astiav.FindDecoderByName(*decoderCodecName)
// No codec
if decCodec == nil {
@@ -122,20 +124,6 @@ func main() {
}
c.Add(decCodecContext.Free)
// Loop through codec hardware configs
for _, p := range decCodec.HardwareConfigs() {
// Valid hardware config
if p.MethodFlags().Has(astiav.CodecHardwareConfigMethodFlagHwDeviceCtx) && p.HardwareDeviceType() == hardwareDeviceType {
hardwarePixelFormat = p.PixelFormat()
break
}
}
// No valid hardware pixel format
if hardwarePixelFormat == astiav.PixelFormatNone {
log.Fatal(errors.New("main: hardware device type not supported by decoder"))
}
// Update codec context
if err := is.CodecParameters().ToCodecContext(decCodecContext); err != nil {
log.Fatal(fmt.Errorf("main: updating codec context failed: %w", err))
@@ -148,6 +136,20 @@ func main() {
}
c.Add(hardwareDeviceContext.Free)
hardwareFramesConstraints := hardwareDeviceContext.HardwareFramesConstraints()
if hardwareFramesConstraints == nil {
log.Fatal("main: hardware frames constraints is nil")
return
}
defer hardwareFramesConstraints.Free()
validHardwarePixelFormats := hardwareFramesConstraints.ValidHardwarePixelFormats()
if len(validHardwarePixelFormats) == 0 {
log.Fatal("main: no valid hardware pixel formats")
return
}
hardwarePixelFormat = validHardwarePixelFormats[0]
// Update decoder context
decCodecContext.SetHardwareDeviceContext(hardwareDeviceContext)
decCodecContext.SetPixelFormatCallback(func(pfs []astiav.PixelFormat) astiav.PixelFormat {
@@ -160,9 +162,9 @@ func main() {
return astiav.PixelFormatNone
})
// Open codec context
// Open decoder context
if err := decCodecContext.Open(decCodec, nil); err != nil {
log.Fatal(fmt.Errorf("main: opening codec context failed: %w", err))
log.Fatal(fmt.Errorf("main: opening decoder context failed: %w", err))
}
break
}

View File

@@ -5,6 +5,7 @@ import (
"flag"
"fmt"
"log"
"slices"
"strings"
"github.com/asticode/go-astiav"
@@ -55,6 +56,19 @@ func main() {
}
defer hardwareDeviceContext.Free()
hardwareFramesConstraints := hardwareDeviceContext.HardwareFramesConstraints()
if hardwareFramesConstraints == nil {
log.Fatal("main: hardware frames constraints is nil")
return
}
defer hardwareFramesConstraints.Free()
validHardwarePixelFormats := hardwareFramesConstraints.ValidHardwarePixelFormats()
if len(validHardwarePixelFormats) == 0 {
log.Fatal("main: no valid hardware pixel formats")
return
}
// Find encoder codec
encCodec := astiav.FindEncoderByName(*encoderCodecName)
if encCodec == nil {
@@ -72,6 +86,8 @@ func main() {
hardwarePixelFormat := astiav.FindPixelFormatByName(*hardwarePixelFormatName)
if hardwarePixelFormat == astiav.PixelFormatNone {
log.Fatal("main: hardware pixel format not found")
} else if !slices.Contains(validHardwarePixelFormats, hardwarePixelFormat) {
log.Fatalf("main: hardware pixel format not supported : %s", hardwarePixelFormat)
}
// Set codec context
@@ -88,10 +104,18 @@ func main() {
}
defer hardwareFramesContext.Free()
validSoftwarePixelFormats := hardwareFramesConstraints.ValidSoftwarePixelFormats()
if len(validSoftwarePixelFormats) == 0 {
log.Fatal("main: no valid software pixel formats")
return
}
// Get software pixel format
softwarePixelFormat := astiav.FindPixelFormatByName(*softwarePixelFormatName)
if softwarePixelFormat == astiav.PixelFormatNone {
log.Fatal("main: software pixel format not found")
} else if !slices.Contains(validSoftwarePixelFormats, softwarePixelFormat) {
log.Fatalf("main: software pixel format not supported : %s", softwarePixelFormat)
}
// Set hardware frame content

View File

@@ -30,6 +30,11 @@ func CreateHardwareDeviceContext(t HardwareDeviceType, device string, options *D
return &hdc, nil
}
// https://ffmpeg.org/doxygen/7.0/hwcontext_8c.html#a80f4c1184e1758150b6d9bc0adf2c1df
func (hdc *HardwareDeviceContext) HardwareFramesConstraints() *HardwareFramesConstraints {
return newHardwareFramesConstraintsFromC(C.av_hwdevice_get_hwframe_constraints(hdc.c, nil))
}
func (hdc *HardwareDeviceContext) Free() {
if hdc.c != nil {
C.av_buffer_unref(&hdc.c)

View File

@@ -0,0 +1,70 @@
package astiav
//#include <libavutil/hwcontext.h>
import "C"
import "unsafe"
// https://ffmpeg.org/doxygen/7.0/structAVHWFramesConstraints.html
type HardwareFramesConstraints struct {
c *C.AVHWFramesConstraints
}
func newHardwareFramesConstraintsFromC(c *C.AVHWFramesConstraints) *HardwareFramesConstraints {
if c == nil {
return nil
}
return &HardwareFramesConstraints{c: c}
}
func (hfc *HardwareFramesConstraints) pixelFormats(formats *C.enum_AVPixelFormat) (o []PixelFormat) {
if formats == nil {
return nil
}
size := unsafe.Sizeof(*formats)
for i := 0; ; i++ {
p := *(*C.int)(unsafe.Pointer(uintptr(unsafe.Pointer(formats)) + uintptr(i)*size))
if p == C.AV_PIX_FMT_NONE {
break
}
o = append(o, PixelFormat(p))
}
return
}
// https://ffmpeg.org/doxygen/7.0/structAVHWFramesConstraints.html#a4258bbe81f927b76b7ca5af44ba7ef6b
func (hfc *HardwareFramesConstraints) ValidHardwarePixelFormats() (o []PixelFormat) {
return hfc.pixelFormats(hfc.c.valid_hw_formats)
}
// https://ffmpeg.org/doxygen/7.0/structAVHWFramesConstraints.html#aabea88093c6f85d6185ffb0852a2217f
func (hfc *HardwareFramesConstraints) ValidSoftwarePixelFormats() (o []PixelFormat) {
return hfc.pixelFormats(hfc.c.valid_sw_formats)
}
// https://ffmpeg.org/doxygen/7.0/structAVHWFramesConstraints.html#af220776925452091085139081d5d7251
func (hfc *HardwareFramesConstraints) MinWidth() int {
return int(hfc.c.min_width)
}
// https://ffmpeg.org/doxygen/7.0/structAVHWFramesConstraints.html#a3f1aec6d1c90f77837875c2a3598be46
func (hfc *HardwareFramesConstraints) MinHeight() int {
return int(hfc.c.min_height)
}
// https://ffmpeg.org/doxygen/7.0/structAVHWFramesConstraints.html#a34e06e3397af2b83de9d78f893bf4168
func (hfc *HardwareFramesConstraints) MaxWidth() int {
return int(hfc.c.max_width)
}
// https://ffmpeg.org/doxygen/7.0/structAVHWFramesConstraints.html#af5d3a683727f7b92abca7b7114d4e15c
func (hfc *HardwareFramesConstraints) MaxHeight() int {
return int(hfc.c.max_height)
}
// https://ffmpeg.org/doxygen/7.0/hwcontext_8c.html#a29da7fa7ffa73266d1cbfccb116ed634
func (hfc *HardwareFramesConstraints) Free() {
if hfc.c != nil {
C.av_hwframe_constraints_free(&hfc.c)
hfc.c = nil
}
}