#!/usr/local/bin/perl use Net::UPnP::ControlPoint; use Net::UPnP::AV::MediaServer; use Shell qw(curl ffmpeg); #curl('--version'); #ffmpeg('-version'); #------------------------------ # program info #------------------------------ $program_name = 'DLNA Media Sever 2 Vodcast'; $copy_right = 'Copyright (c) 2005 Satoshi Konno'; $script_name = 'dms2vodcast.pl'; $script_version = '1.0.3'; #------------------------------ # global variables #------------------------------ @dms_content_list = (); #------------------------------ # command option #------------------------------ $rss_file_name = ""; $base_directory = "./"; $rss_base_url= "http://localhost"; $rss_description = "CyberGarage Vodcast"; $rss_language = ""; $rss_link= ""; $rss_title = "CyberGarage"; $requested_count = 0; $mp4_format = 'ipod'; $title_regexp = ""; @command_opt = ( ['-b', '--base-url', '', 'Set the base url in the item link property of the output RSS file'], ['-B', '--base-directory', '', 'Set the base directory to output the RSS file and the MPEG4 files'], ['-d', '--rss-description', '', 'Set the description tag in the output RSS file'], ['-g', '--rss-language', '', 'Set the language tag in the output RSS file'], ['-h', '--help', '', 'This is help text.'], ['-l', '--rss-link', '', 'Set the link tag in the output RSS file'], ['-r', '--requested-count', '', 'Set the max request count to the media server contents'], ['-t', '--rss-title', '', 'Set the title tag in the output RSS file'], ['-f', '--mp4-format', '', 'Set the MPEG4 format'], ['-s', '--search-title', '', 'Set the regular expression of the content titles by UTF-8'], ); sub is_command_option { ($opt) = @_; for ($n=0; $n<@command_opt; $n++) { if ($opt eq $command_opt[$n][0] || $opt eq $command_opt[$n][1]) { return $n; } } return -1; } #------------------------------ # main (pase command line) #------------------------------ for ($i=0; $i<(@ARGV); $i++) { $opt = $ARGV[$i]; $opt_num = is_command_option($opt); $opt_short_name = ''; if ($opt_num < 0) { if ($opt =~ m/^-/) { print "$script_name : option $opt is unknown\n"; print "$script_name : try \'$script_name --help\' for more information \n"; exit 1; } } else { $opt_short_name = $command_opt[$opt_num][0]; } if ($opt_short_name eq '-h') { print "Usage : $script_name [options...] \n"; print "Options : \n"; $max_opt_output_len = 0; for ($n=0; $n<@command_opt; $n++) { $opt_output_len = length("$command_opt[$n][0]\/$command_opt[$n][1] $command_opt[$n][2]"); if ($max_opt_output_len <= $opt_output_len) { $max_opt_output_len = $opt_output_len; } } for ($n=0; $n<@command_opt; $n++) { $opt_output_str = "$command_opt[$n][0]\/$command_opt[$n][1] $command_opt[$n][2]"; print $opt_output_str; for ($j=0; $j<($max_opt_output_len-length($opt_output_str)); $j++) { print " "; } print " $command_opt[$n][3]\n"; } exit 1; } elsif ($opt_short_name eq '-b') { $rss_base_url = $ARGV[++$i]; } elsif ($opt_short_name eq '-B') { $base_directory = $ARGV[++$i]; } elsif ($opt_short_name eq '-d') { $rss_description = $ARGV[++$i]; } elsif ($opt_short_name eq '-g') { $rss_language = $ARGV[++$i]; } elsif ($opt_short_name eq '-l') { $rss_link = $ARGV[++$i]; } elsif ($opt_short_name eq '-r') { $requested_count = $ARGV[++$i]; } elsif ($opt_short_name eq '-t') { $rss_title = $ARGV[++$i]; } elsif ($opt_short_name eq '-f') { $mp4_format = $ARGV[++$i]; if ($mp4_format ne 'ipod' && $mp4_format ne 'psp') { print "Unkown MPEG4 format : $mp4_format !!\n"; exit 1; } } elsif ($opt_short_name eq '-s') { $title_regexp = $ARGV[++$i]; } else { $rss_file_name = $opt; } } if (length($rss_file_name) <= 0) { print "$script_name : Must specify a output RSS file name\n"; print "$script_name : try \'$script_name --help\' for more information \n"; exit 1 ; } print "$program_name (v$script_version), $copy_right\n"; print "Output RSS file name = $rss_file_name\n"; print " title : $rss_title\n"; print " description : $rss_description\n"; print " language : $rss_language\n"; print " base url : $rss_base_url\n"; print " base directory : $base_directory\n"; print " requested_count : $requested_count\n"; print " mp4_format : $mp4_format\n"; print " search regexp : $title_regexp\n"; #------------------------------ # main #------------------------------ my $obj = Net::UPnP::ControlPoint->new(); $retry_cnt = 0; @dev_list = (); while (@dev_list <= 0 || $retry_cnt > 5) { # @dev_list = $obj->search(st =>'urn:schemas-upnp-org:device:MediaServer:1', mx => 10); @dev_list = $obj->search(st =>'upnp:rootdevice', mx => 3); $retry_cnt++; } $devNum= 0; foreach $dev (@dev_list) { $device_type = $dev->getdevicetype(); if ($device_type ne 'urn:schemas-upnp-org:device:MediaServer:1') { next; } unless ($dev->getservicebyname('urn:schemas-upnp-org:service:ContentDirectory:1')) { next; } print "[$devNum] : " . $dev->getfriendlyname() . "\n"; $mediaServer = Net::UPnP::AV::MediaServer->new(); $mediaServer->setdevice($dev); #@content_list = $mediaServer->getcontentlist(ObjectID => 0, RequestedCount => $requested_count); @content_list = $mediaServer->getcontentlist(ObjectID => 0); #print "content_list = @content_list\n"; foreach $content (@content_list) { parse_content_directory($mediaServer, $content); } $devNum++; } #------------------------------ # Output RSS file #------------------------------ if (@dms_content_list <= 0) { print "Couldn't find video contents !!\n"; exit 1; } $output_rss_filename = $base_directory . $rss_file_name; open(RSS_FILE, ">$output_rss_filename") || die "Couldn't open the specifed output file($output_rss_filename)\n"; $rss_header = <<"RSS_HEADER"; $rss_title $rss_language $rss_description $rss_link RSS_HEADER print RSS_FILE $rss_header; foreach $content (@dms_content_list){ $title = $content->{'title'}; $fname = $content->{'file_name'}; $fsize = $content->{'file_size'}; $mp4_link = $rss_base_url . $fname; $mp4_item = <<"RSS_MP4_ITEM"; $title $mp4_link RSS_MP4_ITEM print RSS_FILE $mp4_item; } $rss_footer = <<"RSS_FOOTER"; RSS_FOOTER print RSS_FILE $rss_footer; close(RSS_FILE); $rss_outputed_items = @dms_content_list; print "Outputed $rss_outputed_items RSS items to $output_rss_filename\n"; #------------------------------ # parse_content_directory #------------------------------ sub parse_content_directory { ($mediaServer, $content) = @_; my $objid = $content->getid(); if ($content->isitem()) { my $title = $content->gettitle(); my $mime = $content->getcontenttype(); if ( ($mime =~ m/video/) && ( (length($title_regexp) == 0) || ($title =~ m/$title_regexp/) ) ) { my $dms_content_count = @dms_content_list; if ($requested_count == 0 || $dms_content_count < $requested_count) { my $mp4_content = mpeg2tompeg4($mediaServer, $content); if (defined($mp4_content)) { push(@dms_content_list, $mp4_content); } } } } unless ($content->iscontainer()) { return; } my @child_content_list = $mediaServer->getcontentlist(ObjectID => $objid ); if (@child_content_list <= 0) { return; } foreach my $child_content (@child_content_list) { parse_content_directory($mediaServer, $child_content); } } #------------------------------ # mpeg2tompeg4 #------------------------------ sub mpeg2tompeg4 { ($mediaServer, $content) = @_; my $objid = $content->getid(); my $title = $content->gettitle(); my $url = $content->geturl(); print "[$objid] $title ($url)\n"; my $dev = $mediaServer->getdevice(); my $dev_friendlyname = $dev->getfriendlyname(); my $dev_udn = $dev->getudn(); $dev_udn =~ s/:/-/g; my $filename_body = $dev_friendlyname . "_" . $dev_udn . "_" . $objid; $filename_body =~ s/ //g; $filename_body =~ s/\//-/g; my $mpeg2_file_name = $filename_body . ".mpeg"; my $mpeg4_file_name = $filename_body . "_" . $mp4_format . ".m4v"; my $output_mpeg4_file_name = $base_directory . $mpeg4_file_name; if (!(-e $output_mpeg4_file_name)) { $curl_opt = "\"$url\" -o \"$mpeg2_file_name\""; print "curl $curl_opt\n"; curl($curl_opt); if ($mp4_format eq 'psp') { $ffmpeg_opt = "-y -i \"$mpeg2_file_name\" -bitexact -fixaspect -s 320x240 -r 29.97 -b 768 -ar 24000 -ab 32 -f psp \"$output_mpeg4_file_name\""; } else { $ffmpeg_opt = "-y -i \"$mpeg2_file_name\" -bitexact -fixaspect -s 320x240 -r 29.97 -b 850 -acodec aac -ac 2 -ar 44100 -ab 64 -f mp4 \"$output_mpeg4_file_name\""; } print "ffmpeg $ffmpeg_opt\n"; ffmpeg($ffmpeg_opt); unlink($mpeg2_file_name); } if (!(-e $output_mpeg4_file_name)) { return undef; } my $mpeg4_file_size = -s $output_mpeg4_file_name; if ($mpeg4_file_size <= 0) { return undef; } my %info = ( 'objid' => $objid, 'title' => $title, 'file_name' => $mpeg4_file_name, 'file_size' => $mpeg4_file_size, ); return \%info; } exit 0;