mirror of
https://github.com/go-gst/go-gst.git
synced 2025-10-05 07:56:51 +08:00
add ability to retrieve a golang color.Palette from a given video format
This commit is contained in:
@@ -41,7 +41,7 @@ func createPipeline() (*gst.Pipeline, error) {
|
||||
// Specify the format we want to provide as application into the pipeline
|
||||
// by creating a video info with the given format and creating caps from it for the appsrc element.
|
||||
videoInfo := video.NewInfo().
|
||||
WithFormat(video.FormatRGBx, width, height).
|
||||
WithFormat(video.FormatRGBA, width, height).
|
||||
WithFPS(gst.Fraction(2, 1))
|
||||
|
||||
src.SetCaps(videoInfo.ToCaps())
|
||||
@@ -50,6 +50,9 @@ func createPipeline() (*gst.Pipeline, error) {
|
||||
// Initialize a frame counter
|
||||
var i int
|
||||
|
||||
// Get all 256 colors in the RGB8P palette.
|
||||
palette := video.FormatRGB8P.Palette()
|
||||
|
||||
// Since our appsrc element operates in pull mode (it asks us to provide data),
|
||||
// we add a handler for the need-data callback and provide new data from there.
|
||||
// In our case, we told gstreamer that we do 2 frames per second. While the
|
||||
@@ -58,23 +61,25 @@ func createPipeline() (*gst.Pipeline, error) {
|
||||
// this handler will be called (on average) twice per second.
|
||||
src.SetCallbacks(&app.SourceCallbacks{
|
||||
NeedDataFunc: func(self *app.Source, _ uint) {
|
||||
if i == 100 {
|
||||
|
||||
// If we've reached the end of the palette, end the stream.
|
||||
if i == len(palette) {
|
||||
src.EndStream()
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Producing frame:", i)
|
||||
|
||||
// Produce an image frame for this iteration.
|
||||
pixels := produceImageFrame(i)
|
||||
|
||||
// Create a buffer that can hold exactly one video RGBx frame.
|
||||
// Create a buffer that can hold exactly one video RGBA frame.
|
||||
buf := gst.NewBufferWithSize(videoInfo.Size())
|
||||
|
||||
// For each frame we produce, we set the timestamp when it should be displayed
|
||||
// The autovideosink will use this information to display the frame at the right time.
|
||||
buf.SetPresentationTimestamp(time.Duration(i) * 500 * time.Millisecond)
|
||||
|
||||
// Produce an image frame for this iteration.
|
||||
pixels := produceImageFrame(palette[i])
|
||||
|
||||
// At this point, buffer is only a reference to an existing memory region somewhere.
|
||||
// When we want to access its content, we have to map it while requesting the required
|
||||
// mode of access (read, read/write).
|
||||
@@ -94,12 +99,11 @@ func createPipeline() (*gst.Pipeline, error) {
|
||||
return pipeline, nil
|
||||
}
|
||||
|
||||
func produceImageFrame(i int) []uint8 {
|
||||
func produceImageFrame(c color.Color) []uint8 {
|
||||
upLeft := image.Point{0, 0}
|
||||
lowRight := image.Point{width, height}
|
||||
img := image.NewRGBA(image.Rectangle{upLeft, lowRight})
|
||||
|
||||
c := getColor(i)
|
||||
for x := 0; x < width; x++ {
|
||||
for y := 0; y < height; y++ {
|
||||
img.Set(x, y, c)
|
||||
@@ -109,26 +113,6 @@ func produceImageFrame(i int) []uint8 {
|
||||
return img.Pix
|
||||
}
|
||||
|
||||
func getColor(i int) color.Color {
|
||||
color := color.RGBA{}
|
||||
if i%2 == 0 {
|
||||
color.R = 0
|
||||
} else {
|
||||
color.R = 255
|
||||
}
|
||||
if i%3 == 0 {
|
||||
color.G = 0
|
||||
} else {
|
||||
color.G = 255
|
||||
}
|
||||
if i%5 == 0 {
|
||||
color.B = 0
|
||||
} else {
|
||||
color.B = 255
|
||||
}
|
||||
return color
|
||||
}
|
||||
|
||||
func handleMessage(msg *gst.Message) error {
|
||||
defer msg.Unref() // Messages are a good candidate for trying out runtime finalizers
|
||||
|
||||
|
@@ -29,6 +29,10 @@ func fromCoreCaps(caps *gst.Caps) *C.GstCaps {
|
||||
return (*C.GstCaps)(unsafe.Pointer(caps.Instance()))
|
||||
}
|
||||
|
||||
func fromCoreCapsFeatures(feats *gst.CapsFeatures) *C.GstCapsFeatures {
|
||||
return (*C.GstCapsFeatures)(unsafe.Pointer(feats.Instance()))
|
||||
}
|
||||
|
||||
func fromCoreElement(elem *gst.Element) *C.GstElement {
|
||||
return (*C.GstElement)(unsafe.Pointer(elem.Instance()))
|
||||
}
|
||||
|
@@ -31,8 +31,11 @@ guint formatInfoWSub (GstVideoFormatInfo * info, guint c)
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"image/color"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"github.com/tinyzimmer/go-gst/gst"
|
||||
)
|
||||
|
||||
// Format is an enum value describing the most common video formats.
|
||||
@@ -138,9 +141,113 @@ const (
|
||||
FormatY412BE Format = C.GST_VIDEO_FORMAT_Y412_BE // (95) – packed 4:4:4:4 YUV, 12 bits per channel(U-Y-V-A...) (Since: 1.18)
|
||||
FormatY412LE Format = C.GST_VIDEO_FORMAT_Y412_LE // (96) – packed 4:4:4:4 YUV, 12 bits per channel(U-Y-V-A...) (Since: 1.18)
|
||||
FormatNV124L4 Format = C.GST_VIDEO_FORMAT_NV12_4L4 // (97) – NV12 with 4x4 tiles in linear order.
|
||||
FormatNV1232L32Format Format = C.GST_VIDEO_FORMAT_NV12_32L32 // (98) – NV12 with 32x32 tiles in linear order.
|
||||
FormatNV1232L32 Format = C.GST_VIDEO_FORMAT_NV12_32L32 // (98) – NV12 with 32x32 tiles in linear order.
|
||||
)
|
||||
|
||||
// AllFormats is a convenience function for retrieving all formats for inspection purposes.
|
||||
// This is not really intended for use in an application, and moreso for debugging.
|
||||
func AllFormats() []Format {
|
||||
return []Format{
|
||||
FormatI420,
|
||||
FormatYV12,
|
||||
FormatYUY2,
|
||||
FormatUYVY,
|
||||
FormatAYUV,
|
||||
FormatRGBx,
|
||||
FormatBGRx,
|
||||
FormatxRGB,
|
||||
FormatxBGR,
|
||||
FormatRGBA,
|
||||
FormatBGRA,
|
||||
FormatARGB,
|
||||
FormatABGR,
|
||||
FormatRGB,
|
||||
FormatBGR,
|
||||
FormatY41B,
|
||||
FormatY42B,
|
||||
FormatYVYU,
|
||||
FormatY444,
|
||||
Formatv210,
|
||||
Formatv216,
|
||||
FormatNV12,
|
||||
FormatNV21,
|
||||
FormatGray8,
|
||||
FormatGray16BE,
|
||||
FormatGray16LE,
|
||||
Formatv308,
|
||||
FormatRGB16,
|
||||
FormatBGR16,
|
||||
FormatRGB15,
|
||||
FormatBGR15,
|
||||
FormatUYVP,
|
||||
FormatA420,
|
||||
FormatRGB8P,
|
||||
FormatYUV9,
|
||||
FormatYVU9,
|
||||
FormatIYU1,
|
||||
FormatARGB64,
|
||||
FormatAYUV64,
|
||||
Formatr210,
|
||||
FormatI42010BE,
|
||||
FormatI42010LE,
|
||||
FormatI42210BE,
|
||||
FormatI42210LE,
|
||||
FormatY44410BE,
|
||||
FormatY44410LE,
|
||||
FormatGBR,
|
||||
FormatGBR10BE,
|
||||
FormatGBR10LE,
|
||||
FormatNV16,
|
||||
FormatNV24,
|
||||
FormatNV1264Z32,
|
||||
FormatA42010BE,
|
||||
FormatA42010LE,
|
||||
FormatA42210BE,
|
||||
FormatA42210LE,
|
||||
FormatA44410BE,
|
||||
FormatA44410LE,
|
||||
FormatNV61,
|
||||
FormatP01010BE,
|
||||
FormatP01010LE,
|
||||
FormatIYU2,
|
||||
FormatVYUY,
|
||||
FormatGBRA,
|
||||
FormatGBRA10BE,
|
||||
FormatGBRA10LE,
|
||||
FormatGBR12BE,
|
||||
FormatGBR12LE,
|
||||
FormatGBRA12BE,
|
||||
FormatGBRA12LE,
|
||||
FormatI42012BE,
|
||||
FormatI42012LE,
|
||||
FormatI42212BE,
|
||||
FormatI42212LE,
|
||||
FormatY44412BE,
|
||||
FormatY44412LE,
|
||||
FormatGray10LE32,
|
||||
FormatNV1210LE32,
|
||||
FormatNV1610LE32,
|
||||
FormatNV1210LE40,
|
||||
FormatY210,
|
||||
FormatY410,
|
||||
FormatVUYA,
|
||||
FormatBGR10A2LE,
|
||||
FormatRGB10A2LE,
|
||||
FormatY44416BE,
|
||||
FormatY44416LE,
|
||||
FormatP016BE,
|
||||
FormatP016LE,
|
||||
FormatP012BE,
|
||||
FormatP012LE,
|
||||
FormatY212BE,
|
||||
FormatY212LE,
|
||||
FormatY412BE,
|
||||
FormatY412LE,
|
||||
FormatNV124L4,
|
||||
FormatNV1232L32,
|
||||
}
|
||||
}
|
||||
|
||||
// RawFormats returns a slice of all the raw video formats supported by GStreamer.
|
||||
func RawFormats() []Format {
|
||||
var size C.guint
|
||||
@@ -152,6 +259,37 @@ func RawFormats() []Format {
|
||||
return out
|
||||
}
|
||||
|
||||
// MakeRawCaps returns a generic raw video caps for formats defined in formats. If formats is empty or nil, returns a caps for
|
||||
// all the supported raw video formats, see RawFormats.
|
||||
func MakeRawCaps(formats []Format) *gst.Caps {
|
||||
var caps *C.GstCaps
|
||||
if len(formats) == 0 {
|
||||
caps = C.gst_video_make_raw_caps(nil, C.guint(0))
|
||||
} else {
|
||||
caps = C.gst_video_make_raw_caps(
|
||||
(*C.GstVideoFormat)(unsafe.Pointer(&formats[0])),
|
||||
C.guint(len(formats)),
|
||||
)
|
||||
}
|
||||
return gst.FromGstCapsUnsafe(unsafe.Pointer(caps))
|
||||
}
|
||||
|
||||
// MakeRawCapsWithFeatures returns a generic raw video caps for formats defined in formats with features. If formats is
|
||||
// empty or nil, returns a caps for all the supported video formats, see RawFormats.
|
||||
func MakeRawCapsWithFeatures(formats []Format, features *gst.CapsFeatures) *gst.Caps {
|
||||
var caps *C.GstCaps
|
||||
if len(formats) == 0 {
|
||||
caps = C.gst_video_make_raw_caps_with_features(nil, C.guint(0), fromCoreCapsFeatures(features))
|
||||
} else {
|
||||
caps = C.gst_video_make_raw_caps_with_features(
|
||||
(*C.GstVideoFormat)(unsafe.Pointer(&formats[0])),
|
||||
C.guint(len(formats)),
|
||||
fromCoreCapsFeatures(features),
|
||||
)
|
||||
}
|
||||
return gst.FromGstCapsUnsafe(unsafe.Pointer(caps))
|
||||
}
|
||||
|
||||
// Info returns the FormatInfo for this video format.
|
||||
func (f Format) Info() *FormatInfo {
|
||||
finfo := C.gst_video_format_get_info(C.GstVideoFormat(f))
|
||||
@@ -160,6 +298,29 @@ func (f Format) Info() *FormatInfo {
|
||||
return info
|
||||
}
|
||||
|
||||
// Palette returns the color palette for this format, or nil if the format does not have one.
|
||||
// At time of writing, RGB8P appears to be the only format with it's own palette.
|
||||
func (f Format) Palette() color.Palette {
|
||||
var size C.gsize
|
||||
ptr := C.gst_video_format_get_palette(C.GstVideoFormat(f), &size)
|
||||
if ptr == nil {
|
||||
return nil
|
||||
}
|
||||
paletteBytes := make([]uint8, int64(size))
|
||||
for i, t := range (*[1 << 30]uint8)(ptr)[:int(size):int(size)] {
|
||||
paletteBytes[i] = t
|
||||
}
|
||||
return bytesToColorPalette(paletteBytes)
|
||||
}
|
||||
|
||||
func bytesToColorPalette(in []uint8) color.Palette {
|
||||
palette := make([]color.Color, len(in)/4)
|
||||
for i := 0; i < len(in); i += 4 {
|
||||
palette[i/4] = color.RGBA{in[i], in[i+1], in[i+2], in[i+3]}
|
||||
}
|
||||
return color.Palette(palette)
|
||||
}
|
||||
|
||||
// String implements a stringer on a Format.
|
||||
func (f Format) String() string {
|
||||
return C.GoString(C.gst_video_format_to_string(C.GstVideoFormat(f)))
|
||||
|
Reference in New Issue
Block a user