Repository: pion/mediadevices
Pull request #58 (2020-02-15 22:20:50)

Fix openh264 incorrect chroma stride
Before openh264 expected to get I444. But, since we now convert the reader to I420, the chroma stride that it's being used in C++ is no longer correct.



Patch:
diff --git a/pkg/codec/openh264/bridge.cpp b/pkg/codec/openh264/bridge.cpp
index 0cfa2f9..83dea41 100644
--- a/pkg/codec/openh264/bridge.cpp
+++ b/pkg/codec/openh264/bridge.cpp
@@ -83,11 +83,9 @@ Slice enc_encode(Encoder *e, Frame f) {
   pic.iPicWidth = f.width;
   pic.iPicHeight = f.height;
   pic.iColorFormat = videoFormatI420;
-  // Since we're using 4:2:0 format, we can set the stride for the chromas
-  // to be the the width of the frame. That way we can skip even rows.
-  // For example, if we have a picture of 400x400, our chroma will be 400x200
-  // from Go.
-  pic.iStride[0] = pic.iStride[1] = pic.iStride[2] = pic.iPicWidth;
+  // We always received I420 format
+  pic.iStride[0] = pic.iPicWidth;
+  pic.iStride[1] = pic.iStride[2] = pic.iPicWidth / 2;
   pic.pData[0] = (unsigned char *)f.y;
   pic.pData[1] = (unsigned char *)f.u;
   pic.pData[2] = (unsigned char *)f.v;
diff --git a/pkg/driver/wrapper.go b/pkg/driver/wrapper.go
index e4c45dc..a751415 100644
--- a/pkg/driver/wrapper.go
+++ b/pkg/driver/wrapper.go
@@ -66,8 +66,16 @@ func (w *adapterWrapper) Close() error {
 	return w.state.Update(StateClosed, w.Adapter.Close)
 }
 
+func (w *adapterWrapper) Properties() []prop.Media {
+	if w.state == StateClosed {
+		return nil
+	}
+
+	return w.Adapter.Properties()
+}
+
 func (w *adapterWrapper) VideoRecord(p prop.Media) (r video.Reader, err error) {
-	w.state.Update(StateRunning, func() error {
+	err = w.state.Update(StateRunning, func() error {
 		r, err = w.VideoRecorder.VideoRecord(p)
 		return err
 	})
@@ -75,7 +83,7 @@ func (w *adapterWrapper) VideoRecord(p prop.Media) (r video.Reader, err error) {
 }
 
 func (w *adapterWrapper) AudioRecord(p prop.Media) (r audio.Reader, err error) {
-	w.state.Update(StateRunning, func() error {
+	err = w.state.Update(StateRunning, func() error {
 		r, err = w.AudioRecorder.AudioRecord(p)
 		return err
 	})


Test patch:
diff --git a/pkg/driver/wrapper_test.go b/pkg/driver/wrapper_test.go
new file mode 100644
index 0000000..619fa4c
--- /dev/null
+++ b/pkg/driver/wrapper_test.go
@@ -0,0 +1,73 @@
+package driver
+
+import (
+	"testing"
+
+	"github.com/pion/mediadevices/pkg/io/audio"
+	"github.com/pion/mediadevices/pkg/io/video"
+	"github.com/pion/mediadevices/pkg/prop"
+)
+
+type adapterMock struct{}
+
+func (a *adapterMock) Open() error              { return nil }
+func (a *adapterMock) Close() error             { return nil }
+func (a *adapterMock) Properties() []prop.Media { return []prop.Media{prop.Media{}} }
+
+type videoAdapterMock struct{ adapterMock }
+
+func (a *videoAdapterMock) VideoRecord(p prop.Media) (r video.Reader, err error) { return nil, nil }
+
+type audioAdapterMock struct{ adapterMock }
+
+func (a *audioAdapterMock) AudioRecord(p prop.Media) (r audio.Reader, err error) { return nil, nil }
+
+func TestVideoWrapperState(t *testing.T) {
+	var a videoAdapterMock
+	d := wrapAdapter(&a, Info{})
+
+	if d.Properties() != nil {
+		t.Errorf("expected nil, but got %v", d.Properties())
+	}
+
+	vr := d.(VideoRecorder)
+	_, err := vr.VideoRecord(prop.Media{})
+	if err == nil {
+		t.Errorf("expected to get an invalid state")
+	}
+
+	err = d.Open()
+	if err != nil {
+		t.Errorf("expected to successfully open, but got %v", err)
+	}
+
+	_, err = vr.VideoRecord(prop.Media{})
+	if err != nil {
+		t.Errorf("expected to successfully start recording, but got %v", err)
+	}
+}
+
+func TestAudioWrapperState(t *testing.T) {
+	var a audioAdapterMock
+	d := wrapAdapter(&a, Info{})
+
+	if d.Properties() != nil {
+		t.Errorf("expected nil, but got %v", d.Properties())
+	}
+
+	ar := d.(AudioRecorder)
+	_, err := ar.AudioRecord(prop.Media{})
+	if err == nil {
+		t.Errorf("expected to get an invalid state")
+	}
+
+	err = d.Open()
+	if err != nil {
+		t.Errorf("expected to successfully open, but got %v", err)
+	}
+
+	_, err = ar.AudioRecord(prop.Media{})
+	if err != nil {
+		t.Errorf("expected to successfully start recording, but got %v", err)
+	}
+}