Lesson 7 : MPEG : Decoding I Frames


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