-
Notifications
You must be signed in to change notification settings - Fork 136
[VPX] add vpx decoder #648
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e3733ad
to
1884644
Compare
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #648 +/- ##
==========================================
+ Coverage 44.76% 45.27% +0.51%
==========================================
Files 81 82 +1
Lines 5605 5661 +56
==========================================
+ Hits 2509 2563 +54
Misses 2921 2921
- Partials 175 177 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
1884644
to
d30d981
Compare
pkg/codec/vpx/vpx_decoder.go
Outdated
status := C.decodeFrame(d.codec, (*C.uint8_t)(&data[0]), C.uint(len(data))) | ||
if status != C.VPX_CODEC_OK { | ||
fmt.Println("Decode failed", status) | ||
panic("Decode failed") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: consider return values instead of panic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Thanks for the catch. Added an error code.
pkg/codec/vpx/vpx_decoder.go
Outdated
"github.com/pion/mediadevices/pkg/prop" | ||
) | ||
|
||
type Decoder struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All packages under mediadevices/pkg/codec
implements the unified encoder interface which reads video/audio from mediadevices/pkg/io/audio.Reader
(which reads mediadevices/pkg/wave.Audio
)/mediadevices/pkg/io/video.Reader
(which reads image.Image
) and returns encoded bytes.
mediadevices/pkg/codec/codec.go
Lines 125 to 147 in 6047a32
// AudioEncoderBuilder is the interface that wraps basic operations that are | |
// necessary to build the audio encoder. | |
// | |
// This interface is for codec implementors to provide codec specific params, | |
// but still giving generality for the users. | |
type AudioEncoderBuilder interface { | |
// RTPCodec represents the codec metadata | |
RTPCodec() *RTPCodec | |
// BuildAudioEncoder builds audio encoder by given media params and audio input | |
BuildAudioEncoder(r audio.Reader, p prop.Media) (ReadCloser, error) | |
} | |
// VideoEncoderBuilder is the interface that wraps basic operations that are | |
// necessary to build the video encoder. | |
// | |
// This interface is for codec implementors to provide codec specific params, | |
// but still giving generality for the users. | |
type VideoEncoderBuilder interface { | |
// RTPCodec represents the codec metadata | |
RTPCodec() *RTPCodec | |
// BuildVideoEncoder builds video encoder by given media params and video input | |
BuildVideoEncoder(r video.Reader, p prop.Media) (ReadCloser, error) | |
} |
But this Decoder
returns images in the codec specific format and the interface can't be shared among the codecs.
In my opinion, decoder interface should be defined at mediadevices/pkg/codec
and the interface should be able to be shared among the codecs.
If this decoder really need to return the data in codec specific format, the name should be something like RawDecoder
to leave Decoder
for unified API available.
pkg/codec/vpx/vpx_decoder.go
Outdated
func (d *Decoder) Decode(data []byte) error { | ||
if len(data) == 0 { | ||
return fmt.Errorf("empty data") | ||
} | ||
status := C.decodeFrame(d.codec, (*C.uint8_t)(&data[0]), C.uint(len(data))) | ||
if status != C.VPX_CODEC_OK { | ||
return fmt.Errorf("Decode failed: %v", status) | ||
} | ||
return nil | ||
} | ||
|
||
func (d *Decoder) GetFrame() *VpxImage { | ||
var iter C.vpx_codec_iter_t = nil // initialize to NULL to start iteration | ||
img := C.getFrame(d.codec, &iter) | ||
if img == nil { | ||
return nil | ||
} | ||
return &VpxImage{img: img} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume the reason having Decode/GetFrame
is that the number of the input byte stream and the output frames aren't always matched.
In this case, it's better to have a similar (symmetric) API with the encoder:
Something like
type VideoDecoderBuilder interface {
BuildVideoDecoder(r io.Reader, p prop.Media) (video.Reader, error)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestion, I made the change in the followup commit.
pkg/codec/vpx/vpx_image.go
Outdated
import "C" | ||
import "unsafe" | ||
|
||
type VpxImage struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Users don't have a safe way to release the data.
Also to make the Decoder
interface unified among the codecs, the decoder should return image.Image
.
mediadevices/io/video.Reader
returns release function along with image.Image
.
So, the image implementing image.Image
may have C.vpx_image_t
internally and have release function written in CGO.
BTW, in Go's naming convention, this would be VPXImage
. https://go.dev/wiki/CodeReviewComments#initialisms
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @at-wat , as you suggested, I changed the interface to use image.Image, so removed this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The interface looks good! Added a suggestion for handling multiple frames for one decode call without dropping.
pkg/codec/vpx/vpx_decoder.go
Outdated
n, err := d.reader.Read(d.buf) | ||
if err != nil { | ||
return nil, nil, err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
io.Reader
is discouraged to return zero byte without a non-nil error. https://pkg.go.dev/io#Reader
So, basically io.Reader
blocks if there are no remained data.
vpx_codec_decode
may decode multiple frames for one vpx_codec_decode
call, but the current code reads only one frame for each Read and remained frames will be buffered.
The current code seems to read the all buffered frames when the reader returns n=0, err=nil
.
However, the reader usually doesn't return n=0, err=nil
and blocks until next data arrival, remained frames never read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bc7653c
I think this should fix reading on such case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @at-wat , good catch.
Thanks @at-wat , all comments are super helpful and quite to the point. It seems all your comments are addressed, so I will go ahead and merge since we have other repo depends on this PR. Meanwhile, if you have any further comments, I am happy to open another PR to address. Thanks for understanding. |
Description
Add vpx decoder (VP8)