Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 1 | #!/usr/bin/perl |
| 2 | |
| 3 | # (C) Sergey Kandaurov |
| 4 | # (C) Nginx, Inc. |
| 5 | |
| 6 | # Tests for mp4 module. |
| 7 | # Ensures that requested stream duration is given with sane accuracy. |
| 8 | |
| 9 | ############################################################################### |
| 10 | |
| 11 | use warnings; |
| 12 | use strict; |
| 13 | |
| 14 | use Test::More; |
| 15 | |
| 16 | BEGIN { use FindBin; chdir($FindBin::Bin); } |
| 17 | |
| 18 | use lib 'lib'; |
Maxim Dounin | 758f406 | 2020-11-17 17:39:09 +0300 | [diff] [blame] | 19 | use Test::Nginx qw/ :DEFAULT http_content /; |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 20 | |
| 21 | ############################################################################### |
| 22 | |
| 23 | select STDERR; $| = 1; |
| 24 | select STDOUT; $| = 1; |
| 25 | |
Sergey Kandaurov | 109fea7 | 2014-04-08 19:31:14 +0400 | [diff] [blame] | 26 | my $t = Test::Nginx->new()->has(qw/http mp4/)->has_daemon('ffprobe') |
| 27 | ->has_daemon('ffmpeg') |
Sergey Kandaurov | d82add7 | 2014-04-11 17:24:34 +0400 | [diff] [blame] | 28 | ->write_file_expand('nginx.conf', <<'EOF'); |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 29 | |
| 30 | %%TEST_GLOBALS%% |
| 31 | |
| 32 | daemon off; |
| 33 | |
| 34 | events { |
| 35 | } |
| 36 | |
| 37 | http { |
| 38 | %%TEST_GLOBALS_HTTP%% |
| 39 | |
| 40 | server { |
Andrey Zelenkov | e59bf36 | 2016-07-12 17:39:03 +0300 | [diff] [blame] | 41 | listen 127.0.0.1:8080; |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 42 | server_name localhost; |
| 43 | |
| 44 | location / { |
| 45 | mp4; |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | EOF |
| 51 | |
Sergey Kandaurov | d82add7 | 2014-04-11 17:24:34 +0400 | [diff] [blame] | 52 | plan(skip_all => 'no lavfi') |
| 53 | unless grep /lavfi/, `ffmpeg -loglevel quiet -formats`; |
Sergey Kandaurov | c7a0585 | 2018-01-11 19:23:45 +0300 | [diff] [blame] | 54 | system('ffmpeg -nostdin -loglevel quiet -y ' |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 55 | . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' |
| 56 | . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 ' |
| 57 | . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v libx264 ' |
| 58 | . "${\($t->testdir())}/test.mp4") == 0 |
| 59 | or die "Can't create mp4 file: $!"; |
Sergey Kandaurov | c7a0585 | 2018-01-11 19:23:45 +0300 | [diff] [blame] | 60 | system('ffmpeg -nostdin -loglevel quiet -y ' |
Sergey Kandaurov | bc6d978 | 2016-09-19 19:09:45 +0300 | [diff] [blame] | 61 | . '-f lavfi -i testsrc=duration=10:size=320x200:rate=15 ' |
| 62 | . '-f lavfi -i testsrc=duration=20:size=320x200:rate=15 ' |
| 63 | . '-map 0:0 -map 1:0 -pix_fmt yuv420p -g 15 -c:v libx264 ' |
| 64 | . '-movflags +faststart ' |
| 65 | . "${\($t->testdir())}/no_mdat.mp4") == 0 |
| 66 | or die "Can't create mp4 file: $!"; |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 67 | |
Sergey Kandaurov | ac4ecc8 | 2020-03-12 15:56:11 +0300 | [diff] [blame] | 68 | my $sbad = <<'EOF'; |
| 69 | 00000000: 00 00 00 1c 66 74 79 70 69 73 6f 6d 00 00 02 00 |....ftypisom....| |
| 70 | 00000010: 69 73 6f 6d 69 73 6f 32 6d 70 34 31 00 00 00 09 |isomiso2mp41....| |
| 71 | 00000020: 6d 64 61 74 00 00 00 00 94 6d 6f 6f 76 00 00 00 |mdat.....moov...| |
| 72 | 00000030: 8c 74 72 61 6b 00 00 00 84 6d 64 69 61 00 00 00 |.trak....mdia...| |
| 73 | 00000040: 7c 6d 69 6e 66 00 00 00 74 73 74 62 6c 00 00 00 ||minf...tstbl...| |
| 74 | 00000050: 18 73 74 74 73 00 00 00 00 00 00 00 01 00 00 03 |.stts...........| |
| 75 | 00000060: 3a 00 00 04 00 00 00 00 28 73 74 73 63 00 00 00 |:.......(stsc...| |
| 76 | 00000070: 00 00 00 00 02 00 00 00 01 00 00 03 0f 00 00 00 |................| |
| 77 | 00000080: 01 00 00 00 02 00 00 00 2b 00 00 00 01 00 00 00 |........+.......| |
| 78 | 00000090: 14 73 74 73 7a 00 00 00 00 00 00 05 a9 00 00 03 |.stsz...........| |
| 79 | 000000a0: 3b 00 00 00 18 63 6f 36 34 00 00 00 00 00 00 00 |;....co64.......| |
| 80 | 000000b0: 01 ff ff ff ff f0 0f fb e7 |.........| |
| 81 | EOF |
| 82 | |
| 83 | $t->write_file('bad.mp4', unhex($sbad)); |
| 84 | $t->run()->plan(27); |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 85 | |
| 86 | ############################################################################### |
| 87 | |
Sergey Kandaurov | bc6d978 | 2016-09-19 19:09:45 +0300 | [diff] [blame] | 88 | my $test_uri = '/test.mp4'; |
| 89 | |
| 90 | again: |
| 91 | |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 92 | is(durations($t, 0.0), '10.0 20.0', 'start zero'); |
| 93 | is(durations($t, 2), '8.0 18.0', 'start integer'); |
| 94 | is(durations($t, 7.1), '2.9 12.9', 'start float'); |
| 95 | |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 96 | is(durations($t, 6, 9), '3.0 3.0', 'start end integer'); |
| 97 | is(durations($t, 2.7, 5.6), '2.9 2.9', 'start end float'); |
| 98 | |
| 99 | is(durations($t, undef, 9), '9.0 9.0', 'end integer'); |
| 100 | is(durations($t, undef, 5.6), '5.6 5.6', 'end float'); |
| 101 | |
| 102 | # invalid range results in ignoring end argument |
| 103 | |
Sergey Kandaurov | bc6d978 | 2016-09-19 19:09:45 +0300 | [diff] [blame] | 104 | like(http_head("$test_uri?start=1&end=1"), qr/200 OK/, 'zero range'); |
| 105 | like(http_head("$test_uri?start=1&end=0"), qr/200 OK/, 'negative range'); |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 106 | |
Sergey Kandaurov | feba339 | 2014-04-07 20:25:39 +0400 | [diff] [blame] | 107 | # start/end values exceeding track/file duration |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 108 | |
Sergey Kandaurov | bc6d978 | 2016-09-19 19:09:45 +0300 | [diff] [blame] | 109 | unlike(http_head("$test_uri?end=11"), qr!HTTP/1.1 500!, |
Sergey Kandaurov | feba339 | 2014-04-07 20:25:39 +0400 | [diff] [blame] | 110 | 'end beyond short track'); |
Sergey Kandaurov | bc6d978 | 2016-09-19 19:09:45 +0300 | [diff] [blame] | 111 | unlike(http_head("$test_uri?end=21"), qr!HTTP/1.1 500!, 'end beyond EOF'); |
| 112 | unlike(http_head("$test_uri?start=11"), qr!HTTP/1.1 500!, |
Sergey Kandaurov | 1466b93 | 2014-04-07 20:25:40 +0400 | [diff] [blame] | 113 | 'start beyond short track'); |
Sergey Kandaurov | bc6d978 | 2016-09-19 19:09:45 +0300 | [diff] [blame] | 114 | like(http_head("$test_uri?start=21"), qr!HTTP/1.1 500!, 'start beyond EOF'); |
| 115 | |
| 116 | $test_uri = '/no_mdat.mp4', goto again unless $test_uri eq '/no_mdat.mp4'; |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 117 | |
Sergey Kandaurov | ac4ecc8 | 2020-03-12 15:56:11 +0300 | [diff] [blame] | 118 | # corrupted formats |
| 119 | |
Sergey Kandaurov | ac4ecc8 | 2020-03-12 15:56:11 +0300 | [diff] [blame] | 120 | like(http_get("/bad.mp4?start=0.5"), qr/500 Internal/, 'co64 chunk beyond EOF'); |
| 121 | |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 122 | ############################################################################### |
| 123 | |
| 124 | sub durations { |
| 125 | my ($t, $start, $end) = @_; |
| 126 | my $path = $t->{_testdir} . '/frag.mp4'; |
| 127 | |
Sergey Kandaurov | bc6d978 | 2016-09-19 19:09:45 +0300 | [diff] [blame] | 128 | my $uri = $test_uri; |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 129 | if (defined $start) { |
| 130 | $uri .= "?start=$start"; |
| 131 | if (defined $end) { |
| 132 | $uri .= "&end=$end"; |
| 133 | } |
| 134 | |
| 135 | } elsif (defined $end) { |
| 136 | $uri .= "?end=$end"; |
| 137 | } |
| 138 | |
Maxim Dounin | 758f406 | 2020-11-17 17:39:09 +0300 | [diff] [blame] | 139 | $t->write_file('frag.mp4', http_content(http_get($uri))); |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 140 | |
| 141 | my $r = `ffprobe -show_streams $path 2>/dev/null`; |
| 142 | Test::Nginx::log_core('||', $r); |
| 143 | sprintf "%.1f %.1f", $r =~ /duration=(\d+\.\d+)/g; |
| 144 | } |
| 145 | |
Sergey Kandaurov | ac4ecc8 | 2020-03-12 15:56:11 +0300 | [diff] [blame] | 146 | sub unhex { |
| 147 | my ($input) = @_; |
| 148 | my $buffer = ''; |
| 149 | |
| 150 | for my $l ($input =~ m/: +((?:[0-9a-f]{2,4} +)+) /gms) { |
| 151 | for my $v ($l =~ m/[0-9a-f]{2}/g) { |
| 152 | $buffer .= chr(hex($v)); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | return $buffer; |
| 157 | } |
| 158 | |
Sergey Kandaurov | 706382e | 2014-03-26 19:58:00 +0400 | [diff] [blame] | 159 | ############################################################################### |