1#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))]
22
23pub mod aac;
24pub mod audio;
25pub mod av1;
26pub mod avc;
27pub mod file;
28pub mod header;
29pub mod hevc;
30pub mod script;
31pub mod tag;
32pub mod video;
33
34pub use crate::file::FlvFile;
35pub use crate::header::FlvHeader;
36pub use crate::tag::{FlvTag, FlvTagData, FlvTagType};
37
38#[cfg(test)]
39#[cfg_attr(all(test, coverage_nightly), coverage(off))]
40mod tests {
41 use std::collections::HashMap;
42 use std::io;
43 use std::path::PathBuf;
44
45 use bytes::Bytes;
46 use scuffle_aac::{AudioObjectType, PartialAudioSpecificConfig};
47 use scuffle_amf0::Amf0Value;
48 use scuffle_av1::seq::SequenceHeaderObu;
49 use scuffle_av1::ObuHeader;
50 use scuffle_h264::{Sps, SpsExtended};
51
52 use crate::aac::AacPacket;
53 use crate::audio::{AudioData, AudioDataBody, SoundRate, SoundSize, SoundType};
54 use crate::av1::Av1Packet;
55 use crate::avc::AvcPacket;
56 use crate::file::FlvFile;
57 use crate::hevc::HevcPacket;
58 use crate::script::ScriptData;
59 use crate::tag::FlvTagData;
60 use crate::video::{EnhancedPacket, FrameType, VideoFourCC, VideoTagBody, VideoTagHeader};
61
62 #[test]
63 fn test_demux_flv_avc_aac() {
64 let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../assets");
65
66 let data = Bytes::from(std::fs::read(dir.join("avc_aac.flv")).expect("failed to read file"));
67 let mut reader = io::Cursor::new(data);
68
69 let flv = FlvFile::demux(&mut reader).expect("failed to demux flv");
70
71 assert_eq!(flv.header.version, 1);
72 assert!(flv.header.has_audio);
73 assert!(flv.header.has_video);
74 assert_eq!(flv.header.extra.len(), 0);
75
76 let mut tags = flv.tags.into_iter();
77
78 {
80 let tag = tags.next().expect("expected tag");
81 assert_eq!(tag.timestamp_ms, 0);
82 assert_eq!(tag.stream_id, 0);
83
84 let script_data = match tag.data {
86 FlvTagData::ScriptData(ScriptData { name, data }) => {
87 assert_eq!(name, "onMetaData");
88 data
89 }
90 _ => panic!("expected script data"),
91 };
92
93 let object = match &script_data[0] {
95 Amf0Value::Object(object) => object,
96 _ => panic!("expected object"),
97 };
98
99 let object = object.iter().map(|(k, v)| (k.as_ref(), v)).collect::<HashMap<_, _>>();
100
101 let audio_sample_size = match object.get("audiosamplesize") {
103 Some(Amf0Value::Number(number)) => number,
104 _ => panic!("expected audio sample size"),
105 };
106
107 assert_eq!(audio_sample_size, &16.0);
108
109 let audio_sample_rate = match object.get("audiosamplerate") {
111 Some(Amf0Value::Number(number)) => number,
112 _ => panic!("expected audio sample rate"),
113 };
114
115 assert_eq!(audio_sample_rate, &48000.0);
116
117 let stereo = match object.get("stereo") {
119 Some(Amf0Value::Boolean(boolean)) => boolean,
120 _ => panic!("expected stereo"),
121 };
122
123 assert_eq!(stereo, &true);
124
125 let audio_codec_id = match object.get("audiocodecid") {
127 Some(Amf0Value::Number(number)) => number,
128 _ => panic!("expected audio codec id"),
129 };
130
131 assert_eq!(audio_codec_id, &10.0); let video_codec_id = match object.get("videocodecid") {
135 Some(Amf0Value::Number(number)) => number,
136 _ => panic!("expected video codec id"),
137 };
138
139 assert_eq!(video_codec_id, &7.0); let duration = match object.get("duration") {
143 Some(Amf0Value::Number(number)) => number,
144 _ => panic!("expected duration"),
145 };
146
147 assert_eq!(duration, &1.088); let width = match object.get("width") {
151 Some(Amf0Value::Number(number)) => number,
152 _ => panic!("expected width"),
153 };
154
155 assert_eq!(width, &3840.0);
156
157 let height = match object.get("height") {
159 Some(Amf0Value::Number(number)) => number,
160 _ => panic!("expected height"),
161 };
162
163 assert_eq!(height, &2160.0);
164
165 let framerate = match object.get("framerate") {
167 Some(Amf0Value::Number(number)) => number,
168 _ => panic!("expected framerate"),
169 };
170
171 assert_eq!(framerate, &60.0);
172
173 match object.get("videodatarate") {
175 Some(Amf0Value::Number(number)) => number,
176 _ => panic!("expected videodatarate"),
177 };
178
179 match object.get("audiodatarate") {
181 Some(Amf0Value::Number(number)) => number,
182 _ => panic!("expected audiodatarate"),
183 };
184
185 let minor_version = match object.get("minor_version") {
187 Some(Amf0Value::String(number)) => number,
188 _ => panic!("expected minor version"),
189 };
190
191 assert_eq!(minor_version, "512");
192
193 let major_brand = match object.get("major_brand") {
195 Some(Amf0Value::String(string)) => string,
196 _ => panic!("expected major brand"),
197 };
198
199 assert_eq!(major_brand, "iso5");
200
201 let compatible_brands = match object.get("compatible_brands") {
203 Some(Amf0Value::String(string)) => string,
204 _ => panic!("expected compatible brands"),
205 };
206
207 assert_eq!(compatible_brands, "iso5iso6mp41");
208 }
209
210 {
212 let tag = tags.next().expect("expected tag");
213 assert_eq!(tag.timestamp_ms, 0);
214 assert_eq!(tag.stream_id, 0);
215
216 let (frame_type, video_data) = match tag.data {
218 FlvTagData::Video(VideoTagHeader { frame_type, body }) => (frame_type, body),
219 _ => panic!("expected video data"),
220 };
221
222 assert_eq!(frame_type, FrameType::Keyframe);
223
224 let avc_decoder_configuration_record = match video_data {
226 VideoTagBody::Avc(AvcPacket::SequenceHeader(data)) => data,
227 _ => panic!("expected avc sequence header"),
228 };
229
230 assert_eq!(avc_decoder_configuration_record.profile_indication, 100);
233 assert_eq!(avc_decoder_configuration_record.profile_compatibility, 0);
234 assert_eq!(avc_decoder_configuration_record.level_indication, 51); assert_eq!(avc_decoder_configuration_record.length_size_minus_one, 3);
236 assert_eq!(avc_decoder_configuration_record.sps.len(), 1);
237 assert_eq!(avc_decoder_configuration_record.pps.len(), 1);
238 assert_eq!(avc_decoder_configuration_record.extended_config, None);
239
240 let sps = &avc_decoder_configuration_record.sps[0];
241 let sps = Sps::parse(sps.clone()).expect("expected sequence parameter set");
243
244 assert_eq!(sps.profile_idc, 100);
245 assert_eq!(sps.level_idc, 51);
246 assert_eq!(sps.width, 3840);
247 assert_eq!(sps.height, 2160);
248 assert_eq!(sps.frame_rate, 60.0);
249
250 assert_eq!(
251 sps.ext,
252 Some(SpsExtended {
253 chroma_format_idc: 1,
254 bit_depth_luma_minus8: 0,
255 bit_depth_chroma_minus8: 0,
256 })
257 )
258 }
259
260 {
262 let tag = tags.next().expect("expected tag");
263 assert_eq!(tag.timestamp_ms, 0);
264 assert_eq!(tag.stream_id, 0);
265
266 let (data, sound_rate, sound_size, sound_type) = match tag.data {
267 FlvTagData::Audio(AudioData {
268 sound_rate,
269 sound_size,
270 sound_type,
271 body,
272 }) => (body, sound_rate, sound_size, sound_type),
273 _ => panic!("expected audio data"),
274 };
275
276 assert_eq!(sound_rate, SoundRate::Hz44000);
277 assert_eq!(sound_size, SoundSize::Bit16);
278 assert_eq!(sound_type, SoundType::Stereo);
279
280 let data = match data {
282 AudioDataBody::Aac(AacPacket::SequenceHeader(data)) => data,
283 _ => panic!("expected aac sequence header"),
284 };
285
286 let aac_decoder_configuration_record =
289 PartialAudioSpecificConfig::parse(&data).expect("expected aac decoder configuration record");
290
291 assert_eq!(
292 aac_decoder_configuration_record.audio_object_type,
293 AudioObjectType::AacLowComplexity
294 );
295 assert_eq!(aac_decoder_configuration_record.sampling_frequency, 48000);
296 assert_eq!(aac_decoder_configuration_record.channel_configuration, 2);
297 }
298
299 let mut last_timestamp = 0;
301 let mut read_seq_end = false;
302 for tag in tags {
303 assert!(tag.timestamp_ms >= last_timestamp);
304 assert_eq!(tag.stream_id, 0);
305
306 last_timestamp = tag.timestamp_ms;
307
308 match tag.data {
309 FlvTagData::Audio(AudioData {
310 body,
311 sound_rate,
312 sound_size,
313 sound_type,
314 }) => {
315 assert_eq!(sound_rate, SoundRate::Hz44000);
316 assert_eq!(sound_size, SoundSize::Bit16);
317 assert_eq!(sound_type, SoundType::Stereo);
318 match body {
319 AudioDataBody::Aac(AacPacket::Raw(data)) => data,
320 _ => panic!("expected aac raw packet"),
321 };
322 }
323 FlvTagData::Video(VideoTagHeader { frame_type, body }) => {
324 match frame_type {
325 FrameType::Keyframe => (),
326 FrameType::Interframe => (),
327 _ => panic!("expected keyframe or interframe"),
328 }
329
330 match body {
331 VideoTagBody::Avc(AvcPacket::Nalu { .. }) => assert!(!read_seq_end),
332 VideoTagBody::Avc(AvcPacket::EndOfSequence) => {
333 assert!(!read_seq_end);
334 read_seq_end = true;
335 }
336 _ => panic!("expected avc nalu packet: {:?}", body),
337 };
338 }
339 _ => panic!("expected audio data"),
340 };
341 }
342
343 assert!(read_seq_end);
344 }
345
346 #[test]
347 fn test_demux_flv_av1_aac() {
348 let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../assets");
349
350 let data = Bytes::from(std::fs::read(dir.join("av1_aac.flv")).expect("failed to read file"));
351 let mut reader = io::Cursor::new(data);
352
353 let flv = FlvFile::demux(&mut reader).expect("failed to demux flv");
354
355 assert_eq!(flv.header.version, 1);
356 assert!(flv.header.has_audio);
357 assert!(flv.header.has_video);
358 assert_eq!(flv.header.extra.len(), 0);
359
360 let mut tags = flv.tags.into_iter();
361
362 {
364 let tag = tags.next().expect("expected tag");
365 assert_eq!(tag.timestamp_ms, 0);
366 assert_eq!(tag.stream_id, 0);
367
368 let script_data = match tag.data {
370 FlvTagData::ScriptData(ScriptData { name, data }) => {
371 assert_eq!(name, "onMetaData");
372 data
373 }
374 _ => panic!("expected script data"),
375 };
376
377 let object = match &script_data[0] {
379 Amf0Value::Object(object) => object,
380 _ => panic!("expected object"),
381 };
382
383 let object = object.iter().map(|(k, v)| (k.as_ref(), v)).collect::<HashMap<_, _>>();
384
385 let audio_sample_size = match object.get("audiosamplesize") {
387 Some(Amf0Value::Number(number)) => number,
388 _ => panic!("expected audio sample size"),
389 };
390
391 assert_eq!(audio_sample_size, &16.0);
392
393 let audio_sample_rate = match object.get("audiosamplerate") {
395 Some(Amf0Value::Number(number)) => number,
396 _ => panic!("expected audio sample rate"),
397 };
398
399 assert_eq!(audio_sample_rate, &48000.0);
400
401 let stereo = match object.get("stereo") {
403 Some(Amf0Value::Boolean(boolean)) => boolean,
404 _ => panic!("expected stereo"),
405 };
406
407 assert_eq!(stereo, &true);
408
409 let audio_codec_id = match object.get("audiocodecid") {
411 Some(Amf0Value::Number(number)) => number,
412 _ => panic!("expected audio codec id"),
413 };
414
415 assert_eq!(audio_codec_id, &10.0); let video_codec_id = match object.get("videocodecid") {
419 Some(Amf0Value::Number(number)) => number,
420 _ => panic!("expected video codec id"),
421 };
422
423 assert_eq!(video_codec_id, &7.0); let duration = match object.get("duration") {
427 Some(Amf0Value::Number(number)) => number,
428 _ => panic!("expected duration"),
429 };
430
431 assert_eq!(duration, &0.0); let width = match object.get("width") {
435 Some(Amf0Value::Number(number)) => number,
436 _ => panic!("expected width"),
437 };
438
439 assert_eq!(width, &2560.0);
440
441 let height = match object.get("height") {
443 Some(Amf0Value::Number(number)) => number,
444 _ => panic!("expected height"),
445 };
446
447 assert_eq!(height, &1440.0);
448
449 let framerate = match object.get("framerate") {
451 Some(Amf0Value::Number(number)) => number,
452 _ => panic!("expected framerate"),
453 };
454
455 assert_eq!(framerate, &144.0);
456
457 match object.get("videodatarate") {
459 Some(Amf0Value::Number(number)) => number,
460 _ => panic!("expected videodatarate"),
461 };
462
463 match object.get("audiodatarate") {
465 Some(Amf0Value::Number(number)) => number,
466 _ => panic!("expected audiodatarate"),
467 };
468 }
469
470 {
472 let tag = tags.next().expect("expected tag");
473 assert_eq!(tag.timestamp_ms, 0);
474 assert_eq!(tag.stream_id, 0);
475
476 let (body, sound_rate, sound_size, sound_type) = match tag.data {
477 FlvTagData::Audio(AudioData {
478 body,
479 sound_rate,
480 sound_size,
481 sound_type,
482 }) => (body, sound_rate, sound_size, sound_type),
483 _ => panic!("expected audio data"),
484 };
485
486 assert_eq!(sound_rate, SoundRate::Hz44000);
487 assert_eq!(sound_size, SoundSize::Bit16);
488 assert_eq!(sound_type, SoundType::Stereo);
489
490 let data = match body {
492 AudioDataBody::Aac(AacPacket::SequenceHeader(data)) => data,
493 _ => panic!("expected aac sequence header"),
494 };
495
496 let aac_decoder_configuration_record =
499 PartialAudioSpecificConfig::parse(&data).expect("expected aac decoder configuration record");
500
501 assert_eq!(
502 aac_decoder_configuration_record.audio_object_type,
503 AudioObjectType::AacLowComplexity
504 );
505 assert_eq!(aac_decoder_configuration_record.sampling_frequency, 48000);
506 assert_eq!(aac_decoder_configuration_record.channel_configuration, 2);
507 }
508
509 {
511 let tag = tags.next().expect("expected tag");
512 assert_eq!(tag.timestamp_ms, 0);
513 assert_eq!(tag.stream_id, 0);
514
515 let (frame_type, video_data) = match tag.data {
517 FlvTagData::Video(VideoTagHeader { frame_type, body }) => (frame_type, body),
518 _ => panic!("expected video data"),
519 };
520
521 assert_eq!(frame_type, FrameType::Keyframe);
522
523 let config = match video_data {
525 VideoTagBody::Enhanced(EnhancedPacket::Av1(Av1Packet::SequenceStart(config))) => config,
526 _ => panic!("expected av1 sequence header found {:?}", video_data),
527 };
528
529 assert_eq!(config.chroma_sample_position, 0);
530 assert!(config.chroma_subsampling_x); assert!(config.chroma_subsampling_y);
532 assert!(!config.high_bitdepth);
533 assert!(!config.twelve_bit);
534
535 let mut reader = std::io::Cursor::new(config.config_obu);
536
537 let header = ObuHeader::parse(&mut reader).expect("expected obu header");
538
539 let seq_obu = SequenceHeaderObu::parse(header, &mut reader).expect("expected sequence obu");
540
541 assert_eq!(seq_obu.max_frame_height, 1440);
542 assert_eq!(seq_obu.max_frame_width, 2560);
543 }
544
545 let mut last_timestamp = 0;
547 let mut read_seq_end = false;
548 for tag in tags {
549 assert!(tag.timestamp_ms >= last_timestamp || tag.timestamp_ms == 0); assert_eq!(tag.stream_id, 0);
551
552 if tag.timestamp_ms != 0 {
553 last_timestamp = tag.timestamp_ms;
554 }
555
556 match tag.data {
557 FlvTagData::Audio(AudioData {
558 body,
559 sound_rate,
560 sound_size,
561 sound_type,
562 }) => {
563 assert_eq!(sound_rate, SoundRate::Hz44000);
564 assert_eq!(sound_size, SoundSize::Bit16);
565 assert_eq!(sound_type, SoundType::Stereo);
566 match body {
567 AudioDataBody::Aac(AacPacket::Raw(data)) => data,
568 _ => panic!("expected aac raw packet"),
569 };
570 }
571 FlvTagData::Video(VideoTagHeader { frame_type, body }) => {
572 match frame_type {
573 FrameType::Keyframe => (),
574 FrameType::Interframe => (),
575 _ => panic!("expected keyframe or interframe"),
576 }
577
578 match body {
579 VideoTagBody::Enhanced(EnhancedPacket::Av1(Av1Packet::Raw(_))) => {
580 assert!(!read_seq_end)
581 }
582 VideoTagBody::Enhanced(EnhancedPacket::SequenceEnd { video_codec }) => {
583 assert!(!read_seq_end);
584 assert_eq!(video_codec, VideoFourCC::Av1);
585 read_seq_end = true;
586 }
587 _ => panic!("expected av1 raw packet: {:?}", body),
588 };
589 }
590 _ => panic!("expected audio data"),
591 };
592 }
593
594 assert!(read_seq_end);
595 }
596
597 #[test]
598 fn test_demux_flv_hevc_aac() {
599 let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../assets");
600
601 let data = Bytes::from(std::fs::read(dir.join("hevc_aac.flv")).expect("failed to read file"));
602 let mut reader = io::Cursor::new(data);
603
604 let flv = FlvFile::demux(&mut reader).expect("failed to demux flv");
605
606 assert_eq!(flv.header.version, 1);
607 assert!(flv.header.has_audio);
608 assert!(flv.header.has_video);
609 assert_eq!(flv.header.extra.len(), 0);
610
611 let mut tags = flv.tags.into_iter();
612
613 {
615 let tag = tags.next().expect("expected tag");
616 assert_eq!(tag.timestamp_ms, 0);
617 assert_eq!(tag.stream_id, 0);
618
619 let script_data = match tag.data {
621 FlvTagData::ScriptData(ScriptData { name, data }) => {
622 assert_eq!(name, "onMetaData");
623 data
624 }
625 _ => panic!("expected script data"),
626 };
627
628 let object = match &script_data[0] {
630 Amf0Value::Object(object) => object,
631 _ => panic!("expected object"),
632 };
633
634 let object = object.iter().map(|(k, v)| (k.as_ref(), v)).collect::<HashMap<_, _>>();
635
636 let audio_sample_size = match object.get("audiosamplesize") {
638 Some(Amf0Value::Number(number)) => number,
639 _ => panic!("expected audio sample size"),
640 };
641
642 assert_eq!(audio_sample_size, &16.0);
643
644 let audio_sample_rate = match object.get("audiosamplerate") {
646 Some(Amf0Value::Number(number)) => number,
647 _ => panic!("expected audio sample rate"),
648 };
649
650 assert_eq!(audio_sample_rate, &48000.0);
651
652 let stereo = match object.get("stereo") {
654 Some(Amf0Value::Boolean(boolean)) => boolean,
655 _ => panic!("expected stereo"),
656 };
657
658 assert_eq!(stereo, &true);
659
660 let audio_codec_id = match object.get("audiocodecid") {
662 Some(Amf0Value::Number(number)) => number,
663 _ => panic!("expected audio codec id"),
664 };
665
666 assert_eq!(audio_codec_id, &10.0); let video_codec_id = match object.get("videocodecid") {
670 Some(Amf0Value::Number(number)) => number,
671 _ => panic!("expected video codec id"),
672 };
673
674 assert_eq!(video_codec_id, &7.0); let duration = match object.get("duration") {
678 Some(Amf0Value::Number(number)) => number,
679 _ => panic!("expected duration"),
680 };
681
682 assert_eq!(duration, &0.0); let width = match object.get("width") {
686 Some(Amf0Value::Number(number)) => number,
687 _ => panic!("expected width"),
688 };
689
690 assert_eq!(width, &2560.0);
691
692 let height = match object.get("height") {
694 Some(Amf0Value::Number(number)) => number,
695 _ => panic!("expected height"),
696 };
697
698 assert_eq!(height, &1440.0);
699
700 let framerate = match object.get("framerate") {
702 Some(Amf0Value::Number(number)) => number,
703 _ => panic!("expected framerate"),
704 };
705
706 assert_eq!(framerate, &144.0);
707
708 match object.get("videodatarate") {
710 Some(Amf0Value::Number(number)) => number,
711 _ => panic!("expected videodatarate"),
712 };
713
714 match object.get("audiodatarate") {
716 Some(Amf0Value::Number(number)) => number,
717 _ => panic!("expected audiodatarate"),
718 };
719 }
720
721 {
723 let tag = tags.next().expect("expected tag");
724 assert_eq!(tag.timestamp_ms, 0);
725 assert_eq!(tag.stream_id, 0);
726
727 let (body, sound_rate, sound_size, sound_type) = match tag.data {
728 FlvTagData::Audio(AudioData {
729 body,
730 sound_rate,
731 sound_size,
732 sound_type,
733 }) => (body, sound_rate, sound_size, sound_type),
734 _ => panic!("expected audio data"),
735 };
736
737 assert_eq!(sound_rate, SoundRate::Hz44000);
738 assert_eq!(sound_size, SoundSize::Bit16);
739 assert_eq!(sound_type, SoundType::Stereo);
740
741 let data = match body {
743 AudioDataBody::Aac(AacPacket::SequenceHeader(data)) => data,
744 _ => panic!("expected aac sequence header"),
745 };
746
747 let aac_decoder_configuration_record =
750 PartialAudioSpecificConfig::parse(&data).expect("expected aac decoder configuration record");
751
752 assert_eq!(
753 aac_decoder_configuration_record.audio_object_type,
754 AudioObjectType::AacLowComplexity
755 );
756 assert_eq!(aac_decoder_configuration_record.sampling_frequency, 48000);
757 assert_eq!(aac_decoder_configuration_record.channel_configuration, 2);
758 }
759
760 {
762 let tag = tags.next().expect("expected tag");
763 assert_eq!(tag.timestamp_ms, 0);
764 assert_eq!(tag.stream_id, 0);
765
766 let (frame_type, video_data) = match tag.data {
768 FlvTagData::Video(VideoTagHeader { frame_type, body }) => (frame_type, body),
769 _ => panic!("expected video data"),
770 };
771
772 assert_eq!(frame_type, FrameType::Keyframe);
773
774 let config = match video_data {
776 VideoTagBody::Enhanced(EnhancedPacket::Hevc(HevcPacket::SequenceStart(config))) => config,
777 _ => panic!("expected hevc sequence header found {:?}", video_data),
778 };
779
780 assert_eq!(config.configuration_version, 1);
781 assert_eq!(config.avg_frame_rate, 0);
782 assert_eq!(config.constant_frame_rate, 0);
783 assert_eq!(config.num_temporal_layers, 1);
784
785 let Some(sps) = config
787 .arrays
788 .iter()
789 .find(|a| a.nal_unit_type == scuffle_h265::NaluType::Sps)
790 .and_then(|v| v.nalus.first())
791 else {
792 panic!("expected sps");
793 };
794
795 let Some(_) = config
797 .arrays
798 .iter()
799 .find(|a| a.nal_unit_type == scuffle_h265::NaluType::Pps)
800 .and_then(|v| v.nalus.first())
801 else {
802 panic!("expected pps");
803 };
804
805 let sps = scuffle_h265::Sps::parse(sps.clone()).expect("expected sps");
807
808 assert_eq!(sps.frame_rate, 144.0);
809 assert_eq!(sps.width, 2560);
810 assert_eq!(sps.height, 1440);
811 assert_eq!(
812 sps.color_config,
813 Some(scuffle_h265::ColorConfig {
814 full_range: false,
815 color_primaries: 1,
816 transfer_characteristics: 1,
817 matrix_coefficients: 1,
818 })
819 )
820 }
821
822 let mut last_timestamp = 0;
824 let mut read_seq_end = false;
825 for tag in tags {
826 assert!(tag.timestamp_ms >= last_timestamp || tag.timestamp_ms == 0); assert_eq!(tag.stream_id, 0);
828
829 if tag.timestamp_ms != 0 {
830 last_timestamp = tag.timestamp_ms;
831 }
832
833 match tag.data {
834 FlvTagData::Audio(AudioData {
835 body,
836 sound_rate,
837 sound_size,
838 sound_type,
839 }) => {
840 assert_eq!(sound_rate, SoundRate::Hz44000);
841 assert_eq!(sound_size, SoundSize::Bit16);
842 assert_eq!(sound_type, SoundType::Stereo);
843 match body {
844 AudioDataBody::Aac(AacPacket::Raw(data)) => data,
845 _ => panic!("expected aac raw packet"),
846 };
847 }
848 FlvTagData::Video(VideoTagHeader { frame_type, body }) => {
849 match frame_type {
850 FrameType::Keyframe => (),
851 FrameType::Interframe => (),
852 _ => panic!("expected keyframe or interframe"),
853 }
854
855 match body {
856 VideoTagBody::Enhanced(EnhancedPacket::Hevc(HevcPacket::Nalu { .. })) => assert!(!read_seq_end),
857 VideoTagBody::Enhanced(EnhancedPacket::SequenceEnd { video_codec }) => {
858 assert!(!read_seq_end);
859 assert_eq!(video_codec, VideoFourCC::Hevc);
860 read_seq_end = true;
861 }
862 _ => panic!("expected hevc nalu packet: {:?}", body),
863 };
864 }
865 _ => panic!("expected audio data"),
866 };
867 }
868
869 assert!(read_seq_end);
870 }
871}