1# $Id: Probe.pm 2195 2006-08-18 21:43:37Z joern $ 2 3#----------------------------------------------------------------------- 4# Copyright (C) 2001-2006 J�rn Reder <joern AT zyn.de>. 5# All Rights Reserved. See file COPYRIGHT for details. 6# 7# This module is part of Video::DVDRip, which is free software; you can 8# redistribute it and/or modify it under the same terms as Perl itself. 9#----------------------------------------------------------------------- 10 11package Video::DVDRip::Probe; 12use Locale::TextDomain qw (video.dvdrip); 13 14use base Video::DVDRip::Base; 15 16use Carp; 17use strict; 18 19sub width { shift->{width} } 20sub height { shift->{height} } 21sub aspect_ratio { shift->{aspect_ratio} } 22sub video_mode { shift->{video_mode} } 23sub letterboxed { shift->{letterboxed} } 24sub frames { shift->{frames} } 25sub runtime { shift->{runtime} } 26sub frame_rate { shift->{frame_rate} } 27sub bitrates { shift->{bitrates} } # href 28sub audio_tracks { shift->{audio_tracks} } # lref 29sub probe_output { shift->{probe_output} } 30sub audio_probe_output { shift->{audio_probe_output} } 31sub chapters { shift->{chapters} } 32sub viewing_angles { shift->{viewing_angles} } 33 34sub set_width { shift->{width} = $_[1] } 35sub set_height { shift->{height} = $_[1] } 36sub set_aspect_ratio { shift->{aspect_ratio} = $_[1] } 37sub set_video_mode { shift->{video_mode} = $_[1] } 38sub set_letterboxed { shift->{letterboxed} = $_[1] } 39sub set_frames { shift->{frames} = $_[1] } 40sub set_runtime { shift->{runtime} = $_[1] } 41sub set_frame_rate { shift->{frame_rate} = $_[1] } 42sub set_bitrates { shift->{bitrates} = $_[1] } 43sub set_audio_tracks { shift->{audio_tracks} = $_[1] } 44sub set_probe_output { shift->{probe_output} = $_[1] } 45sub set_audio_probe_output { shift->{audio_probe_output} = $_[1] } 46sub set_chapters { shift->{chapters} = $_[1] } 47sub set_viewing_angles { shift->{viewing_angles} = $_[1] } 48 49sub analyze { 50 my $class = shift; 51 my %par = @_; 52 my ( $probe_output, $title ) = @par{ 'probe_output', 'title' }; 53 54 my ( $width, $height, $aspect_ratio, $video_mode, $letterboxed ); 55 my ( $frames, $runtime, $frame_rate, $chapters, $angles ); 56 57 ($width) = $probe_output =~ /frame\s+size:\s*-g\s+(\d+)/; 58 ($height) = $probe_output =~ /frame\s+size:\s*-g\s+\d+x(\d+)/; 59 ($aspect_ratio) = $probe_output =~ /aspect\s*ratio:\s*(\d+:\d+)/; 60 ($video_mode) = $probe_output =~ /dvd_reader.*?(pal|ntsc)/i; 61 ($letterboxed) = $probe_output =~ /dvd_reader.*?(letterboxed)/; 62 ($frames) = $probe_output =~ /V:\s*(\d+)\s*frames/; 63 ($runtime) = $probe_output =~ /playback time:.*?(\d+)\s*sec/; 64 ($frame_rate) = $probe_output =~ /frame\s+rate:\s+-f\s+([\d.]+)/; 65 ($chapters) = $probe_output =~ /(\d+)\s+chapter/; 66 ($angles) = $probe_output =~ /(\d+)\s+angle/; 67 68 $letterboxed = $letterboxed ? 1 : 0; 69 $video_mode = lc($video_mode); 70 71 my ( $size, %bitrates, $bitrate ); 72 while ( $probe_output =~ /CD:\s*(\d+)/g ) { 73 $size = $1; 74 ($bitrate) = $probe_output =~ /CD:\s*$size.*?\@\s*([\d.]+)\s*kbps/; 75 ( $bitrates{$size} ) = int($bitrate); 76 } 77 78 my (@audio_tracks); 79 while ( $probe_output 80 =~ /audio\s+track:\s*-a\s*(\d+).*?-e\s+(\d+),(\d+),(\d+)/g ) { 81 if ( $2 and $3 ) { 82 $audio_tracks[$1] = { 83 sample_rate => $2, 84 sample_width => $3, 85 bitrate => undef, # later set by analyze_audio 86 tc_option_n => undef, # later set by analyze_audio 87 scan_result => undef, # later set by Title->scan 88 }; 89 } 90 } 91 92 my $i = 0; 93 while ( 94 $probe_output =~ /\(dvd_reader.c\)\s+([^\s]+)\s+(\w+).*?(\d+)Ch/g ) { 95 $audio_tracks[$i]->{type} = lc($1); 96 $audio_tracks[$i]->{lang} = lc($2); 97 $audio_tracks[$i]->{channels} = $3; 98 ++$i; 99 } 100 101 # Audio 102 103 my @audio_track_objects; 104 105 $i = 0; 106 foreach my $audio (@audio_tracks) { 107 push @audio_track_objects, 108 Video::DVDRip::Audio->new( 109 title => $title, 110 type => $audio->{type}, 111 lang => $audio->{lang}, 112 channels => $audio->{channels}, 113 sample_rate => $audio->{sample_rate}, 114 tc_nr => $i, 115 tc_target_track => ( $i == 0 ? 0 : -1 ), 116 tc_audio_codec => "mp3", 117 tc_bitrate => 128, 118 tc_mp3_quality => 0, 119 tc_samplerate => $audio->{sample_rate}, 120 ); 121 ++$i; 122 } 123 124 # Subtitles 125 126 my %subtitles; 127 my $sid; 128 while ( $probe_output =~ /subtitle\s+(\d+)=<([^>]+)>/g ) { 129 $sid = $1 + 0; 130 $subtitles{$sid} = Video::DVDRip::Subtitle->new( 131 id => $sid, 132 lang => $2, 133 title => $title, 134 ); 135 } 136 137 # Chapter frame counter 138 my ( $timecode, $last_timecode ); 139 for ( my $i = 2; $i <= $chapters; ++$i ) { 140 ($timecode) = ( $probe_output =~ /CHAPTER0?$i=([\d:.]+)/ ); 141 next if $timecode eq ''; 142 $timecode =~ /(\d+):(\d+):(\d+)\.(\d+)/; 143 $timecode = $1 * 3600 + $2 * 60 + $3 + $4 / 1000; 144 $timecode = int( $timecode * $frame_rate ); 145 $title->chapter_frames->{ $i - 1 } = $timecode - $last_timecode; 146 $last_timecode = $timecode; 147 } 148 149 $title->chapter_frames->{$chapters} = $frames - $timecode if $timecode; 150 151 $title->set_width($width); 152 $title->set_height($height); 153 $title->set_aspect_ratio($aspect_ratio); 154 $title->set_video_mode($video_mode); 155 $title->set_letterboxed($letterboxed); 156 $title->set_frames($frames); 157 $title->set_runtime($runtime); 158 $title->set_frame_rate("$frame_rate"); 159 $title->set_bitrates( \%bitrates ); 160 $title->set_audio_tracks( \@audio_track_objects ); 161 $title->set_chapters($chapters); 162 $title->set_viewing_angles($angles); 163 $title->set_dvd_probe_output($probe_output); 164 $title->set_audio_channel( @audio_tracks ? 0 : -1 ); 165 166 $title->set_subtitles( \%subtitles ); 167 $title->set_selected_subtitle_id(0) if defined $sid; 168 169 1; 170} 171 172sub analyze_audio { 173 my $self = shift; 174 my %par = @_; 175 my ( $probe_output, $title ) = @par{ 'probe_output', 'title' }; 176 177 $title->set_vob_probe_output($probe_output); 178 179 #-- probe audio bitrates 180 my @lines = split( /\n/, $probe_output ); 181 my $nr; 182 for ( my $i = 0; $i < @lines; ++$i ) { 183 if ( $lines[$i] =~ /audio\s+track:\s+-a\s+(\d+).*?-n\s+([x0-9]+)/ ) { 184 $nr = $1; 185 next if not defined $title->audio_tracks->[$nr]; 186 $title->audio_tracks->[$nr]->set_tc_option_n($2); 187 ++$i; 188 $lines[$i] =~ /bitrate\s*=(\d+)/; 189 $title->audio_tracks->[$nr]->set_bitrate($1); 190 $title->audio_tracks->[$nr]->set_tc_ac3_bitrate($1); 191 } 192 } 193 194 #-- probe frame rate (probing from DVD sometimes reports 195 #-- wrong framerates for NTSC movies, so we'll correct this here) 196 my ($frame_rate) = $probe_output =~ /frame\s+rate:\s+-f\s+([\d.]+)/; 197 $title->set_frame_rate("$frame_rate"); 198 199 1; 200} 201 202sub analyze_scan { 203 my $class = shift; 204 my %par = @_; 205 my ( $scan_output, $audio, $count ) 206 = @par{ 'scan_output', 'audio', 'count' }; 207 208 my ($volume_rescale); 209 ($volume_rescale) = $scan_output =~ /rescale=([\d.]+)/; 210 211 return if $volume_rescale eq ''; 212 213 if ( $audio->volume_rescale > $volume_rescale || $count == 0 ) { 214 $audio->set_scan_output($scan_output); 215 $audio->set_volume_rescale($volume_rescale); 216 $audio->set_tc_volume_rescale($volume_rescale); 217 } 218 219 1; 220} 221 222sub analyze_lsdvd { 223 my $class = shift; 224 my %par = @_; 225 my ( $probe_output, $project, $cb_title_probed ) 226 = @par{ 'probe_output', 'project', 'cb_title_probed' }; 227 228 $probe_output =~ s/EXECFLOW_OK//; 229 $probe_output =~ s/^our//; 230 231 my %lsdvd; 232 eval $probe_output; 233 die "Error compiling lsdvd output: $@. Output was:\n$probe_output" if $@; 234 235 my %titles; 236 $project->content->set_titles( \%titles ); 237 238 foreach my $track ( @{ $lsdvd{track} } ) { 239 my $title = $titles{ $track->{ix} } = Video::DVDRip::Title->new( 240 nr => $track->{ix}, 241 project => $project, 242 ); 243 244 my @audio_tracks; 245 foreach my $audio ( @{ $track->{audio} } ) { 246 push @audio_tracks, 247 Video::DVDRip::Audio->new( 248 title => $title, 249 type => $audio->{format}, 250 lang => $audio->{langcode}, 251 channels => $audio->{channels}, 252 sample_rate => $audio->{frequency}, 253 tc_nr => $audio->{ix} - 1, 254 tc_target_track => ( $audio->{ix} == 1 ? 0 : -1 ), 255 tc_audio_codec => "mp3", 256 tc_bitrate => 128, 257 tc_mp3_quality => 0, 258 tc_samplerate => $audio->{frequency}, 259 ); 260 } 261 262 my %subtitles; 263 foreach my $sub ( @{ $track->{subp} } ) { 264 my $sid = hex( $sub->{streamid} ) - 32; 265 $subtitles{$sid} = Video::DVDRip::Subtitle->new( 266 id => $sid, 267 lang => $sub->{langcode}, 268 title => $title, 269 ); 270 } 271 272 my %chapter_frames; 273 foreach my $chap ( @{ $track->{chapter} } ) { 274 $chapter_frames{ $chap->{ix} } 275 = int( $chap->{length} * $track->{fps} ); 276 } 277 278 $track->{aspect} =~ s!/!:!; 279 $title->set_width( $track->{width} ); 280 $title->set_height( $track->{height} ); 281 $title->set_aspect_ratio( $track->{aspect} ); 282 $title->set_video_mode( lc( $track->{format} ) ); 283 $title->set_letterboxed( $track->{df} eq 'Letterbox' ); 284 $title->set_frames( int( $track->{length} * $track->{fps} ) ); 285 $title->set_runtime( int( $track->{length} + 0.5 ) ); 286 $title->set_frame_rate( "$track->{fps}" ); 287 $title->set_chapters( scalar( @{ $track->{chapter} } ) ); 288 $title->set_viewing_angles( $track->{angles} ); 289 $title->set_audio_channel( @audio_tracks ? 0 : -1 ); 290 291 $title->set_audio_tracks( \@audio_tracks ); 292 $title->set_subtitles( \%subtitles ); 293 $title->set_chapter_frames( \%chapter_frames ); 294 $title->set_selected_subtitle_id(0) if @{ $track->{subp} }; 295 296 $title->suggest_transcode_options; 297 298 &$cb_title_probed($title) if $cb_title_probed; 299 } 300 301 1; 302} 303 3041; 305 306