1 // Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
2 // Copyright (C) 2019 Jordan Petridis <jordan@centricular.com>
3 //
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Library General Public
6 // License as published by the Free Software Foundation; either
7 // version 2 of the License, or (at your option) any later version.
8 //
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Library General Public License for more details.
13 //
14 // You should have received a copy of the GNU Library General Public
15 // License along with this library; if not, write to the
16 // Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
17 // Boston, MA 02110-1335, USA.
18 
19 use pretty_assertions::assert_eq;
20 
init()21 fn init() {
22     use std::sync::Once;
23     static INIT: Once = Once::new();
24 
25     INIT.call_once(|| {
26         gst::init().unwrap();
27         gstrsclosedcaption::plugin_register_static().unwrap();
28     });
29 }
30 
31 /// Encode a single raw CEA608 packet and compare the output
32 #[test]
test_encode_single_packet()33 fn test_encode_single_packet() {
34     init();
35 
36     let input = [148, 44];
37     let expected_output = b"Scenarist_SCC V1.0\r\n\r\n11:12:13;14\t942c\r\n\r\n";
38 
39     let mut h = gst_check::Harness::new("sccenc");
40     h.set_src_caps_str("closedcaption/x-cea-608, format=raw, framerate=(fraction)30000/1001");
41     let tc = gst_video::ValidVideoTimeCode::new(
42         gst::Fraction::new(30000, 1001),
43         None,
44         gst_video::VideoTimeCodeFlags::DROP_FRAME,
45         11,
46         12,
47         13,
48         14,
49         0,
50     )
51     .unwrap();
52 
53     let buf = {
54         let mut buf = gst::Buffer::from_mut_slice(Vec::from(&input[..]));
55         let buf_ref = buf.get_mut().unwrap();
56         gst_video::VideoTimeCodeMeta::add(buf_ref, &tc);
57         buf_ref.set_pts(gst::ClockTime::from_seconds(0));
58         buf
59     };
60 
61     assert_eq!(h.push(buf), Ok(gst::FlowSuccess::Ok));
62     h.push_event(gst::event::Eos::new());
63 
64     let buf = h.pull().expect("Couldn't pull buffer");
65 
66     let timecode = buf
67         .meta::<gst_video::VideoTimeCodeMeta>()
68         .expect("No timecode for buffer")
69         .tc();
70     assert_eq!(timecode, tc);
71 
72     let pts = buf.pts().unwrap();
73     assert_eq!(pts, gst::ClockTime::ZERO);
74 
75     let map = buf.map_readable().expect("Couldn't map buffer readable");
76     assert_eq!(
77         std::str::from_utf8(map.as_ref()),
78         std::str::from_utf8(expected_output.as_ref())
79     );
80 }
81 
82 /// Encode a multiple raw CEA608 packets and compare the output
83 #[test]
test_encode_multiple_packets()84 fn test_encode_multiple_packets() {
85     init();
86 
87     let input1 = [148, 44];
88     let input2 = [
89         148, 32, 148, 32, 148, 174, 148, 174, 148, 84, 148, 84, 16, 174, 16, 174, 70, 242, 239,
90         109, 32, 206, 229, 247, 32, 217, 239, 242, 107, 44, 148, 242, 148, 242, 16, 174, 16, 174,
91         244, 104, 233, 115, 32, 233, 115, 32, 196, 229, 109, 239, 227, 242, 97, 227, 121, 32, 206,
92         239, 247, 161, 148, 47, 148, 47,
93     ];
94 
95     let expected_output1 = b"Scenarist_SCC V1.0\r\n\r\n00:00:00;00\t942c 942c\r\n\r\n";
96     let expected_output2 = b"00:00:14;01\t9420 9420 94ae 94ae 9454 9454 10ae 10ae 46f2 ef6d 20ce e5f7 20d9 eff2 6b2c 94f2\r\n\r\n";
97     let expected_output3 = b"00:00:14;17\t94f2 10ae 10ae f468 e973 20e9 7320 c4e5 6def e3f2 61e3 7920 ceef f7a1 942f 942f\r\n\r\n";
98 
99     let mut h = gst_check::Harness::new("sccenc");
100     h.set_src_caps_str("closedcaption/x-cea-608, format=raw, framerate=(fraction)30000/1001");
101     let tc1 = gst_video::ValidVideoTimeCode::new(
102         gst::Fraction::new(30000, 1001),
103         None,
104         gst_video::VideoTimeCodeFlags::DROP_FRAME,
105         0,
106         0,
107         0,
108         0,
109         0,
110     )
111     .unwrap();
112 
113     let tc2 = gst_video::ValidVideoTimeCode::new(
114         gst::Fraction::new(30000, 1001),
115         None,
116         gst_video::VideoTimeCodeFlags::DROP_FRAME,
117         0,
118         0,
119         14,
120         1,
121         0,
122     )
123     .unwrap();
124 
125     let buf1 = {
126         let mut buf = gst::Buffer::from_mut_slice(Vec::from(&input1[..]));
127         let buf_ref = buf.get_mut().unwrap();
128         gst_video::VideoTimeCodeMeta::add(buf_ref, &tc1);
129         buf_ref.set_pts(gst::ClockTime::from_seconds(0));
130         buf
131     };
132 
133     let buf2 = {
134         let mut buf = gst::Buffer::from_mut_slice(Vec::from(&input1[..]));
135         let buf_ref = buf.get_mut().unwrap();
136         let mut tc = tc1.clone();
137         tc.increment_frame();
138         gst_video::VideoTimeCodeMeta::add(buf_ref, &tc);
139         buf_ref.set_pts(gst::ClockTime::from_seconds(0));
140         buf
141     };
142 
143     let mut t = tc2.clone();
144     let mut buffers = input2
145         .chunks(2)
146         .map(move |bytes| {
147             let mut buf = gst::Buffer::from_mut_slice(Vec::from(bytes));
148             let buf_ref = buf.get_mut().unwrap();
149             gst_video::VideoTimeCodeMeta::add(buf_ref, &t);
150             t.increment_frame();
151             buf
152         })
153         .collect::<Vec<gst::Buffer>>();
154     buffers.insert(0, buf1);
155     buffers.insert(1, buf2);
156 
157     buffers.iter().for_each(|buf| {
158         assert_eq!(h.push(buf.clone()), Ok(gst::FlowSuccess::Ok));
159     });
160     h.push_event(gst::event::Eos::new());
161 
162     // Pull 1
163     let buf = h.pull().expect("Couldn't pull buffer");
164 
165     let timecode = buf
166         .meta::<gst_video::VideoTimeCodeMeta>()
167         .expect("No timecode for buffer")
168         .tc();
169     assert_eq!(timecode, tc1);
170 
171     let pts = buf.pts().unwrap();
172     assert_eq!(pts, gst::ClockTime::ZERO);
173 
174     let map = buf.map_readable().expect("Couldn't map buffer readable");
175 
176     assert_eq!(
177         std::str::from_utf8(map.as_ref()),
178         std::str::from_utf8(expected_output1.as_ref())
179     );
180 
181     // Pull 2
182     let buf = h.pull().expect("Couldn't pull buffer");
183     let timecode = buf
184         .meta::<gst_video::VideoTimeCodeMeta>()
185         .expect("No timecode for buffer")
186         .tc();
187     assert_eq!(timecode, tc2);
188 
189     // let pts = buf.get_pts().unwrap();
190     // assert_eq!(pts, gst::ClockTime::ZERO);
191 
192     let map = buf.map_readable().expect("Couldn't map buffer readable");
193     assert_eq!(
194         std::str::from_utf8(map.as_ref()),
195         std::str::from_utf8(expected_output2.as_ref())
196     );
197 
198     let tc3 = gst_video::ValidVideoTimeCode::new(
199         gst::Fraction::new(30000, 1001),
200         None,
201         gst_video::VideoTimeCodeFlags::DROP_FRAME,
202         0,
203         0,
204         14,
205         17,
206         0,
207     )
208     .unwrap();
209 
210     // Pull 3
211     let buf = h.pull().expect("Couldn't pull buffer");
212     let timecode = buf
213         .meta::<gst_video::VideoTimeCodeMeta>()
214         .expect("No timecode for buffer")
215         .tc();
216     assert_eq!(timecode, tc3);
217 
218     // let pts = buf.get_pts().unwrap();
219     // assert_eq!(pts, gst::ClockTime::ZERO);
220 
221     let map = buf.map_readable().expect("Couldn't map buffer readable");
222     assert_eq!(
223         std::str::from_utf8(map.as_ref()),
224         std::str::from_utf8(expected_output3.as_ref())
225     );
226 }
227