#------------------------------------------------------------------------ # # Copyright (c) 1997-1998 by Cornell University. # # See the file "license.txt" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # #------------------------------------------------------------------------ package require DvmBasic package require DvmMpeg package require DvmAvi package require DvmColor #--------------------------------------------------------------- # This script converts a MPEG Video Sequence to a series of ppm # file. #--------------------------------------------------------------- if {$argc != 3} { puts "Usage: $argv0 input output.avi codec :" exit } else { set inname [lindex $argv 0] set outname [lindex $argv 1] set codec [lindex $argv 2] } ############################################################ # Notes: Make sure the avi_stream_close and avi_file_close # get called, even in case of premature ending of the mpeg. # Should put the mpeg_parse stuff is in a catch{}. # iv32 is the fastest, but worst quality # iv50 is the the best quality, but iv41 is the slowest ############################################################ proc swap_buffer {a b} { upvar $a aa upvar $b bb set temp $aa set aa $bb set bb $temp } proc check_bitstream_underflow {bs bp chan size} { set off [bitparser_tell $bp] set left [bitstream_bytes_left $bs $off] if {$left < $size} { bitstream_shift $bs $off bitstream_channel_read $bs $chan $left bitparser_seek $bp 0 } } #---------------------------------------------------------------- # open file, create new bitparser, new bitstream, read first # 65535 bytes from file into bitstream and attached the bitparser # to the bitstream #---------------------------------------------------------------- set bp [bitparser_new] set bs [bitstream_new 65535] set file [open "$inname" r] fconfigure $file -translation binary -buffersize 65535 bitstream_channel_read $bs $file 0 bitparser_wrap $bp $bs #---------------------------------------------------------------- # parse the mpeg sequence header and find out the dimension and # size of the frames. care must be taken if frame is not multiple # of 16 #---------------------------------------------------------------- set hdr [mpeg_seq_hdr_new] mpeg_seq_hdr_find $bp mpeg_seq_hdr_parse $bp $hdr set seq_w [mpeg_seq_hdr_get_width $hdr] set seq_h [mpeg_seq_hdr_get_height $hdr] set pic_size [mpeg_seq_hdr_get_buffer_size $hdr] set rem_w [expr $seq_w % 16] set rem_h [expr $seq_h % 16] if {$rem_w != 0} { set w [expr $seq_w + 16 - $rem_w] } else { set w $seq_w } if {$rem_h != 0} { set h [expr $seq_h + 16 - $rem_h] } else { set h $seq_h } set halfw [expr $w/2] set halfh [expr $h/2] #---------------------------------------------------------------- # allocate a bunch of byte buffer, sc buffer, mv buffer, # mpeg_pic_hdr #---------------------------------------------------------------- set y [byte_new $w $h] set prevy [byte_new $w $h] set futurey [byte_new $w $h] set r [byte_new $seq_w $seq_h] set g [byte_new $seq_w $seq_h] set b [byte_new $seq_w $seq_h] set b_r [byte_new $seq_w $seq_h] set b_g [byte_new $seq_w $seq_h] set b_b [byte_new $seq_w $seq_h] set u [byte_new $halfw $halfh] set prevu [byte_new $halfw $halfh] set futureu [byte_new $halfw $halfh] set v [byte_new $halfw $halfh] set prevv [byte_new $halfw $halfh] set futurev [byte_new $halfw $halfh] set outy [byte_clip $y 0 0 $seq_w $seq_h] set outu [byte_clip $u 0 0 [expr $seq_w/2] [expr $seq_h/2]] set outv [byte_clip $v 0 0 [expr $seq_w/2] [expr $seq_h/2]] set fwdmv [vector_new [expr $w/16] [expr $h/16]] set bwdmv [vector_new [expr $w/16] [expr $h/16]] set scy [sc_new [expr $w/8] [expr $h/8]] set scu [sc_new [expr $w/16] [expr $h/16]] set scv [sc_new [expr $w/16] [expr $h/16]] set fh [mpeg_pic_hdr_new] #---------------------------------------------------------------- # Initialize the AVI writing stuff #---------------------------------------------------------------- set bnum 0 set togo 0 set a_hdr [avi_file_create "$outname"] # Args: hdr codec width height fps keyframeinterval quality bitrate set a_str [avi_video_stream_create $a_hdr $codec $seq_w $seq_h 30 30 75 50000] #---------------------------------------------------------------- # now really start decoding the video frames. in each loop we # make sure there are at least pic_size bytes available in the # bitstream buffer. #---------------------------------------------------------------- set len [mpeg_pic_hdr_find $bp] set counter 0 while {($len != -1)&&($counter < 300)} { check_bitstream_underflow $bs $bp $file $pic_size mpeg_pic_hdr_parse $bp $fh set play_order [mpeg_pic_hdr_get_temporal_ref $fh] set type [mpeg_pic_hdr_get_type $fh] if {$type == "i"} { swap_buffer futurey prevy swap_buffer futureu prevu swap_buffer futurev prevv mpeg_pic_i_parse $bp $hdr $fh $scy $scu $scv sc_i_to_byte $scy $y sc_i_to_byte $scu $u sc_i_to_byte $scv $v yuv_to_rgb_420 $y $u $v $r $g $b swap_buffer y futurey swap_buffer u futureu swap_buffer v futurev } elseif { $type == "p"} { swap_buffer futurey prevy swap_buffer futureu prevu swap_buffer futurev prevv mpeg_pic_p_parse $bp $hdr $fh $scy $scu $scv $fwdmv sc_p_to_y $scy $fwdmv $prevy $y sc_p_to_uv $scu $fwdmv $prevu $u sc_p_to_uv $scv $fwdmv $prevv $v yuv_to_rgb_420 $y $u $v $r $g $b swap_buffer y futurey swap_buffer u futureu swap_buffer v futurev } else { mpeg_pic_b_parse $bp $hdr $fh $scy $scu $scv $fwdmv $bwdmv sc_b_to_y $scy $fwdmv $bwdmv $prevy $futurey $y sc_b_to_uv $scu $fwdmv $bwdmv $prevu $futureu $u sc_b_to_uv $scv $fwdmv $bwdmv $prevv $futurev $v yuv_to_rgb_420 $y $u $v $r $g $b } # Display order conversion code if {$play_order == $togo} { avi_video_frame_write $a_str $r $g $b #puts -nonewline stderr "$play_order " incr togo if {$bnum == $togo} { avi_video_frame_write $a_str $b_r $b_g $b_b #puts -nonewline stderr "$bnum " set bnum 0 incr togo } } elseif {$play_order > $togo} { swap_buffer r b_r swap_buffer g b_g swap_buffer b b_b set bnum $play_order } else { set togo 0 if {$play_order == $togo} { avi_video_frame_write $a_str $r $g $b #puts -nonewline stderr "$play_order " incr togo } else { swap_buffer r b_r swap_buffer g b_g swap_buffer b b_b set bnum $play_order } } mpeg_pic_hdr_find $bp set currCode [mpeg_get_curr_start_code $bp] if {$currCode == "seq-end-code"} { break } incr counter puts -nonewline "$counter " flush stdout } mpeg_pic_hdr_free $fh avi_stream_close $a_str avi_file_close $a_hdr byte_free $y byte_free $prevy byte_free $futurey byte_free $r byte_free $g byte_free $b byte_free $b_r byte_free $b_g byte_free $b_b byte_free $u byte_free $prevu byte_free $futureu byte_free $v byte_free $prevv byte_free $futurev vector_free $fwdmv vector_free $bwdmv sc_free $scy sc_free $scu sc_free $scv