set bitrate for openh264 (#566)

* Added the set bitrate function for openh264

* add examples

* Format

---------

Co-authored-by: Jingyang Kang <3drxkjy@gmail.com>
This commit is contained in:
代码人生
2025-04-06 20:47:23 +08:00
committed by GitHub
parent 2d7bdd4e24
commit cd5f8eb43a
6 changed files with 135 additions and 0 deletions

1
examples/openh264/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
openh264

View File

@@ -0,0 +1,22 @@
## Instructions
### Install required codecs
In this example, we'll be using openh264 as our video codec. Therefore, we need to make sure that these codecs are installed within our system.
Installation steps:
* [openh264](https://github.com/pion/mediadevices#openh264)
### Download archive examplee
```
git clone https://github.com/pion/mediadevices.git
```
### Run openh264 example
Run `cd mediadevices/examples/openh264 && go build && ./openh264 recorded.h264`
set bitrate ,first press `Ctrl+c` or send a SIGINT signal.
To stop recording,second press `Ctrl+c` or send a SIGINT signal.

96
examples/openh264/main.go Normal file
View File

@@ -0,0 +1,96 @@
package main
import (
"fmt"
"image"
"io"
"os"
"os/signal"
"syscall"
"github.com/pion/mediadevices"
"github.com/pion/mediadevices/pkg/codec"
"github.com/pion/mediadevices/pkg/codec/openh264"
_ "github.com/pion/mediadevices/pkg/driver/camera" // This is required to register camera adapter
"github.com/pion/mediadevices/pkg/frame"
"github.com/pion/mediadevices/pkg/io/video"
"github.com/pion/mediadevices/pkg/prop"
)
func must(err error) {
if err != nil {
panic(err)
}
}
func main() {
if len(os.Args) != 2 {
fmt.Printf("usage: %s <path/to/file.h264>\n", os.Args[0])
return
}
dest := os.Args[1]
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT)
params, err := openh264.NewParams()
must(err)
params.BitRate = 1_000_000 // 1mbps
codecSelector := mediadevices.NewCodecSelector(
mediadevices.WithVideoEncoders(&params),
)
mediaStream, err := mediadevices.GetUserMedia(mediadevices.MediaStreamConstraints{
Video: func(c *mediadevices.MediaTrackConstraints) {
c.FrameFormat = prop.FrameFormat(frame.FormatI420)
c.Width = prop.Int(640)
c.Height = prop.Int(480)
},
Codec: codecSelector,
})
must(err)
videoTrack := mediaStream.GetVideoTracks()[0].(*mediadevices.VideoTrack)
defer videoTrack.Close()
videoTrack.Transform(video.TransformFunc(func(r video.Reader) video.Reader {
return video.ReaderFunc(func() (img image.Image, release func(), err error) {
// we send io.EOF signal to the encoder reader to stop reading. Therefore, io.Copy
// will finish its execution and the program will finish
select {
case <-sigs:
return nil, func() {}, io.EOF
default:
}
return r.Read()
})
}))
reader, err := videoTrack.NewEncodedIOReader(params.RTPCodec().MimeType)
must(err)
defer reader.Close()
out, err := os.Create(dest)
must(err)
fmt.Println("Recording... Press Ctrl+c to Set BitRate")
go func() {
_, err = io.Copy(out, reader)
}()
<-sigs
if control, ok := reader.(codec.Controllable); ok {
if ctrl, ok := control.Controller().(codec.KeyFrameController); ok {
fmt.Println("Force Key")
ctrl.ForceKeyFrame()
}
if ctrl, ok := control.Controller().(codec.BitRateController); ok {
fmt.Println("SetBitRate")
ctrl.SetBitRate(200_000)
}
}
fmt.Println("Recording... Press Ctrl+c to stop")
<-sigs
must(err)
fmt.Println("Your video has been recorded to", dest)
}

View File

@@ -69,6 +69,16 @@ void enc_free(Encoder *e, int *eresult) {
free(e);
}
void enc_set_bitrate(Encoder *e, int bitrate) {
SEncParamExt encParamExt;
e->engine->GetOption(ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &encParamExt);
encParamExt.iTargetBitrate=bitrate;
encParamExt.iMaxBitrate=bitrate;
encParamExt.sSpatialLayers[0].iSpatialBitrate = bitrate;
encParamExt.sSpatialLayers[0].iMaxSpatialBitrate = bitrate;
e->engine->SetOption(ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &encParamExt);
}
// There's a good reference from ffmpeg in using the encode_frame
// Reference: https://ffmpeg.org/doxygen/2.6/libopenh264enc_8c_source.html
Slice enc_encode(Encoder *e, Frame f, int *eresult) {

View File

@@ -44,6 +44,7 @@ typedef struct Encoder {
Encoder *enc_new(const EncoderOptions params, int *eresult);
void enc_free(Encoder *e, int *eresult);
Slice enc_encode(Encoder *e, Frame f, int *eresult);
void enc_set_bitrate(Encoder *e, int bitrate);
#ifdef __cplusplus
}
#endif

View File

@@ -96,6 +96,11 @@ func (e *encoder) ForceKeyFrame() error {
return nil
}
func (e *encoder) SetBitRate(bitrate int) error {
C.enc_set_bitrate(e.engine, C.int(bitrate))
return nil
}
func (e *encoder) Controller() codec.EncoderController {
return e
}