Lesson 6 : Mpeg Basic | Lesson 8 : Decoding MPEG P and B Frames | Contents
In this lesson, we will learn about the procedure to decode I Frames from a MPEG Video. We will see ScImage for the first time, and we will use color conversion primitives from DvmColor packages. First, lets load all the packages we need.
cd C:/Dali/doc/tutorial package require DvmBasic package require DvmPnm package require DvmColor package require DvmMpeg
We will assumes that you already know how to write three ByteImages representing a color image into a file (see lesson 3 if you don;t know). We will use a procedure called write_ppm defined in pnmlib.tcl. As in the previous lesson, we open a MPEG video, put it into bitstream, attached a bitparser, and read the sequence header.
source pnmlib.tcl set bs [bitstream_mmap_read_new tennis.mpg] set bp [bitparser_new] bitparser_wrap $bp $bs set seqHdr [mpeg_seq_hdr_new] mpeg_seq_hdr_find $bp mpeg_seq_hdr_parse $bp $seqHdr
We need to allocates a few byte images to store information decoded from the video sequence. ByteImages y, u, and v will store the frames in the YCbCr color space; and r, g, and b will store the frames in the RGB color space.
set w [mpeg_seq_hdr_get_width $seqHdr] set h [mpeg_seq_hdr_get_height $seqHdr] set y [byte_new $w $h] set u [byte_new [expr $w/2] [expr $h/2]] set v [byte_new [expr $w/2] [expr $h/2]] set r [byte_new $w $h] set g [byte_new $w $h] set b [byte_new $w $h]
A compressed video sequence will be parsed and stored into three semi-compressed images. A semi-compressed image is a 2D array of DCT blocks. Each DCT block is in turn a compressed representation for 8x8 pixels. Like ByteImages, ScImages can be created (with sc_new), clipped (with sc_clip), copied (with sc_copy) etc. We now create three ScImages, one for each of the Y, Cr, and Cb planes.
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]]
We are ready to decode the MPEG video. As in the previous lesson, we will have a loop that scans through the sequence and stops when encountering the sequence end marker. However, since we are only interested in decoding the frames, we will use mpeg_pic_hdr_find instead of mpeg_any_hdr_find and skip all other headers. mpeg_pic_hdr_find will return the number of bytes parsed from the BitStream if the picture header is found (-1 otherwise). For each picture header, we parse it and check its type. If the header indicates that the picture is an I-frame, we will decoded it (shown in the next section of code), otherwise we skip the picture and proceed to the next picture header using mpeg_pic_hdr_find.
set picHdr [mpeg_pic_hdr_new] set len [mpeg_pic_hdr_find $bp] while {$len != -1} { mpeg_pic_hdr_parse $bp $picHdr if {[mpeg_pic_hdr_get_type $picHdr] == "i"} { : : } set len [mpeg_pic_hdr_find $bp] }
We will now complete the loop above by filling in the code that decodes the picture. I-Frames can be decoded with mpeg_pic_i_parse. This primitive takes in a bitparser, picture header, sequence header, and initializes three ScImages with DCT blocks from compressed picture data. Then we decode the ScImages to ByteImages with sc_i_to_byte, and finally we perform a color space conversion from YUV to RGB using yuv_to_rgb_420. At this point, we can write the RGB images out to ppm files (left to reader as an exercise).
mpeg_pic_i_parse $bp $seqHdr $picHdr $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
Next, we will describe how to decode P and B frames.
Don't forget to free all memory-allocated variables.
byte_free $y byte_free $u byte_free $v byte_free $r byte_free $g byte_free $b sc_free $scy sc_free $scu sc_free $scv mpeg_pic_hdr_free $picHdr mpeg_seq_hdr_free $seqHdr bitstream_mmap_read_free $bs bitparser_free $bp
Code for this lesson: l7.tcl.
Lesson 6 : Mpeg Basic | Lesson 8 : Decoding MPEG P and B Frames | Contents
Last Updated : 07/18/2025 05:01:04