@@ -61,6 +61,8 @@ and open media files and byte streams.
6161### Demultiplexing
6262
6363``` go
64+ package main
65+
6466import (
6567 media " github.com/mutablelogic/go-media"
6668)
@@ -106,51 +108,82 @@ func main() {
106108
107109### Decoding - Video
108110
109- This example shows you how to decode video frames from a media file into images.
111+ This example shows you how to decode video frames from a media file into images, and
112+ encode those images to JPEG format.
110113
111114``` go
115+ package main
116+
112117import (
113- media " github.com/mutablelogic/go-media"
118+ " context"
119+ " fmt"
120+ " image/jpeg"
121+ " io"
122+ " log"
123+ " os"
124+ " path/filepath"
125+
126+ // Packages
127+ ffmpeg " github.com/mutablelogic/go-media/pkg/ffmpeg"
128+
129+ // Namespace imports
130+ . " github.com/mutablelogic/go-media"
114131)
115132
116133func main () {
117- manager , err := media.NewManager ()
134+ // Open a media file for reading. The format of the file is guessed.
135+ input , err := ffmpeg.Open (os.Args [1 ])
118136 if err != nil {
119137 log.Fatal (err)
120138 }
121139
122- media , err := manager.Open (" etc/test/sample.mp4" , nil )
123- if err != nil {
124- log.Fatal (err)
140+ // Make a map function which can be used to decode the streams and set
141+ // the parameters we want from the decode. The audio and video streams
142+ // are resampled and resized to fit the parameters we pass back the decoder.
143+ mapfunc := func (stream int , par *ffmpeg.Par ) (*ffmpeg.Par , error ) {
144+ if par.Type () == VIDEO {
145+ // Convert frame to yuv420p to frame size and rate as source
146+ return ffmpeg.VideoPar (" yuv420p" , par.WidthHeight (), par.FrameRate ()), nil
147+ }
148+ // Ignore other streams
149+ return nil , nil
125150 }
126- defer media.Close ()
127151
128- // Create a decoder for the media file. Only video streams are decoded
129- decoder , err := media.Decoder (func (stream Stream) (Parameters, error ) {
130- if stream.Type () == VIDEO {
131- // Copy video
132- return stream.Parameters (), nil
133- } else {
134- // Ignore other stream types
135- return nil , nil
136- }
137- })
152+ // Make a folder where we're going to store the thumbnails
153+ tmp , err := os.MkdirTemp (" " , " decode" )
138154 if err != nil {
139155 log.Fatal (err)
140156 }
141157
142- // The frame function is called for each frame in the stream
143- framefn := func (frame Frame) error {
144- image , err := frame.Image ()
158+ // Decode the streams and receive the video frame
159+ // If the map function is nil, the frames are copied. In this example,
160+ // we get a yuv420p frame at the same size as the original.
161+ n := 0
162+ err = input.Decode (context.Background (), mapfunc, func (stream int , frame *ffmpeg.Frame ) error {
163+ // Write the frame to a file
164+ w , err := os.Create (filepath.Join (tmp, fmt.Sprintf (" frame-%d -%d .jpg" , stream, n)))
145165 if err != nil {
146166 return err
147167 }
148- // TODO: Do something with the image here....
149- return nil
150- }
168+ defer w.Close ()
151169
152- // decode frames from the stream
153- if err := decoder.Decode (context.Background (), framefn); err != nil {
170+ // Convert to an image and encode a JPEG
171+ if image , err := frame.Image (); err != nil {
172+ return err
173+ } else if err := jpeg.Encode (w, image, nil ); err != nil {
174+ return err
175+ } else {
176+ log.Println (" Wrote:" , w.Name ())
177+ }
178+
179+ // End after 10 frames
180+ n++
181+ if n >= 10 {
182+ return io.EOF
183+ }
184+ return nil
185+ })
186+ if err != nil {
154187 log.Fatal (err)
155188 }
156189}
@@ -159,68 +192,67 @@ func main() {
159192### Encoding - Audio and Video
160193
161194This example shows you how to encode video and audio frames into a media file.
195+ It creates a testcard signal overlayed with a timestamp, and a 1KHz tone at -5dB
162196
163197``` go
164198package main
165199
166200import (
201+ " fmt"
167202 " io"
168203 " log"
169204 " os"
170- " time"
171205
172- media " github.com/mutablelogic/go-media "
206+ // Packages
173207 ffmpeg " github.com/mutablelogic/go-media/pkg/ffmpeg"
174208 generator " github.com/mutablelogic/go-media/pkg/generator"
175- ff " github.com/mutablelogic/go-media/sys/ffmpeg61"
176209)
177210
211+ // This example encodes an audio an video stream to a file
178212func main () {
179213 // Create a new file with an audio and video stream
180- // 30fps and 22050Hz mono audio
181214 file , err := ffmpeg.Create (os.Args [1 ],
182- ffmpeg.OptStream (1 , ffmpeg.VideoPar (" yuv420p" , " 640x480 " , 30 )),
215+ ffmpeg.OptStream (1 , ffmpeg.VideoPar (" yuv420p" , " 1024x720 " , 30 )),
183216 ffmpeg.OptStream (2 , ffmpeg.AudioPar (" fltp" , " mono" , 22050 )),
184217 )
185218 if err != nil {
186219 log.Fatal (err)
187220 }
188221 defer file.Close ()
189222
190- // Make an video generator which can generate YUV420P frames
191- // with the same parameters as the video stream
192- video , err := generator.NewYUV420P (file.Stream (1 ).Par ())
223+ // Make an video generator which can generate frames with the same
224+ // parameters as the video stream
225+ video , err := generator.NewEBU (file.Stream (1 ).Par ())
193226 if err != nil {
194227 log.Fatal (err)
195228 }
196229 defer video.Close ()
197230
198- // Make an audio generator which can generate a 440Hz tone
231+ // Make an audio generator which can generate a 1KHz tone
199232 // at -5dB with the same parameters as the audio stream
200- audio , err := generator.NewSine (440 , -5 , file.Stream (2 ).Par ())
233+ audio , err := generator.NewSine (1000 , -5 , file.Stream (2 ).Par ())
201234 if err != nil {
202235 log.Fatal (err)
203236 }
204237 defer audio.Close ()
205238
206- // Write 1 min of frames , passing video and audio frames to the encoder
239+ // Write 90 seconds , passing video and audio frames to the encoder
207240 // and returning io.EOF when the duration is reached
208- duration := time. Minute
209- if err : = file.Encode (func (stream int ) (*ff. AVFrame , error ) {
210- var frame media .Frame
241+ duration := float64 ( 90 )
242+ err = file.Encode (func (stream int ) (*ffmpeg. Frame , error ) {
243+ var frame *ffmpeg .Frame
211244 switch stream {
212245 case 1 :
213246 frame = video.Frame ()
214247 case 2 :
215248 frame = audio.Frame ()
216249 }
217- if frame.Time () >= duration {
218- return nil , io.EOF
219- } else {
220- log.Println (" Frame" , stream, " =>" , frame.Time ().Truncate (time.Millisecond ))
221- return frame.(*ffmpeg.Frame ).AVFrame (), nil
250+ if frame != nil && frame.Ts () < duration {
251+ return frame, nil
222252 }
223- }, nil ); err != nil {
253+ return nil , io.EOF
254+ }, nil )
255+ if err != nil {
224256 log.Fatal (err)
225257 }
226258}
233265### Retrieving Metadata and Artwork from a media file
234266
235267Here is an example of opening a media file and retrieving metadata and artwork.
268+ You have to read the artwork separately from the metadata.
236269
237270``` go
238271package main
@@ -241,20 +274,13 @@ import (
241274 " log"
242275 " os"
243276
244- media " github.com/mutablelogic/go-media "
245- file " github.com/mutablelogic/go-media/pkg/file "
277+ // Packages
278+ ffmpeg " github.com/mutablelogic/go-media/pkg/ffmpeg "
246279)
247280
248281func main () {
249- manager , err := media.NewManager ()
250- if err != nil {
251- log.Fatal (err)
252- }
253-
254282 // Open a media file for reading. The format of the file is guessed.
255- // Alteratively, you can pass a format as the second argument. Further optional
256- // arguments can be used to set the format options.
257- reader , err := manager.Open (os.Args [1 ], nil )
283+ reader , err := ffmpeg.Open (os.Args [1 ])
258284 if err != nil {
259285 log.Fatal (err)
260286 }
@@ -268,14 +294,13 @@ func main() {
268294 }
269295
270296 // Retrieve artwork by using the MetaArtwork key. The value is of type []byte.
271- // which needs to be converted to an image. There is a utility method to
272- // detect the image type.
273- for _ , artwork := range reader. Metadata (media. MetaArtwork ) {
274- mimetype , ext , err := file. MimeType (artwork. Value ().([] byte ))
275- if err != nil {
276- log.Fatal (err )
297+ // which needs to be converted to an image.
298+ for _ , artwork := range reader. Metadata (ffmpeg. MetaArtwork ) {
299+ mimetype := artwork. Value ()
300+ if mimetype != " " {
301+ // Retrieve the data using the metadata.Bytes() method
302+ log.Print ( " We got some artwork of mimetype " , mimetype )
277303 }
278- log.Print (" got artwork" , mimetype, ext)
279304 }
280305}
281306```
0 commit comments