Lesson 6 : MPEG : Basic


Lesson 5 : More ByteImage | Lesson 7 : Decoding MPEG I Frames | Contents


In this lesson, we will learn about the basic of MPEG abstraction and primitives. We will develop a small program that prints out basic information about a MPEG-1 Video (the number of frames and GOPs in an MPEG video file).

MPEG abstractions are provided by DvmMpeg package. So before we do anything, load the following packages.

cd C:/Dali/doc/tutorial
package require DvmBasic
package require DvmMpeg

Now we need to open a MPEG video, read it in and store it in a BitStream. As usual, we create a BitParser and attached it the the BitStream. For simplicity, we will memory map the whole file into a BitStream. We will learn about how to read in the video file piece by piece in future. You can subsitute another MPEG video file for tennis.mpg, but MPEG system streams will not work.

set bs [bitstream_mmap_read_new tennis.mpg]
set bp [bitparser_new]
bitparser_wrap $bp $bs

Each MPEG video has a sequence header. It contains information such as width, height and frame rate. To read the sequence header, we position the bitparser in front if the sequence header, and then parse the BitStream. We move the bitparser's cursor by calling mpeg_seq_hdr_find, and we parse the sequence header from the BitStream by calling mpeg_seq_hdr_parse. Mpeg_seq_hdr_find searches the bitstream for a special marker that identifies the beginning of the sequence header, and positions the cursor just before the beginning of the sequence header. Mpeg_seq_hdr_parse assumes that the cursor is positioned at the beginning of the sequence header, reads bits from the bitstream, decodes the information, and store it inside a preallocated sequence header (allocated with mpeg_seq_hdr_new).

set seqHdr [mpeg_seq_hdr_new]
mpeg_seq_hdr_find $bp
mpeg_seq_hdr_parse $bp $seqHdr

Note that although most MPEG video files start with a sequence header, sometimes there is some garbage in the file before the MPEG sequence starts. This is why mpeg_seq_hdr_find is needed. We will see many other find and parse methods in later lessons.

Now that we have read in the sequence header, we retrieve the information from the header and print it out.

puts "Frame Width   : [mpeg_seq_hdr_get_width $seqHdr]"
puts "Frame Height  : [mpeg_seq_hdr_get_height $seqHdr]"
puts "Frame Rate    : [mpeg_seq_hdr_get_pic_rate $seqHdr]"

Let's write a program to print out the number of GOPs and frames in this MPEG video. To do so, we need two counters and a loop. The loop should iterate until we reach the end of the MPEG video, marked by a sequence end code. We use the primitives mpeg_any_hdr_find to position the cursor before any MPEG marker, and mpeg_get_curr_start_code to identify the current marker.

In the main loop, we repeatedly find the next marker. If the marker indicates beginning of a GOP header, we increment the GOP counter.  If the marker indicates beginning of a picture header, we increment the frame counter. After we increment the counters, we need to move to cursor to the end of the headers, so that the next call to mpeg_any_hdr_find will not find the same thing again. This is done by mpeg_gop_hdr_skip and mpeg_pic_hdr_skip. We do the same thing the we encounter a slice header, except that we do not increment any counter.

set gopCount 0
set picCount 0
mpeg_any_hdr_find $bp
set currCode [mpeg_get_curr_start_code $bp]
while {$currCode != "seq-end-code"} {
    if {$currCode == "gop-start-code"} {
	incr gopCount
	mpeg_gop_hdr_skip $bp
    } elseif {$currCode == "pic-start-code"} {
	incr picCount
	mpeg_pic_hdr_skip $bp
    } elseif {$currCode == "slice-start-code"} {
    	mpeg_pic_skip $bp
    }
    mpeg_any_hdr_find $bp
    set currCode [mpeg_get_curr_start_code $bp]
}
puts "Number of GOPs   : $gopCount"
puts "Number of Frames : $picCount"

To summarize: in this lesson we showed three basic abstractions for MPEG Video: mpeg_pic_hdr, mpeg_gop_hdr, and mpeg_seq_hdr. We also showed three basic operations on them:

Before we proceed to the next lesson, remember to clean up the mess we made :) Notice that all bitstreams created by bitstream_mmap_read_new must be freed by bitstream_mmap_read_free and not bitstream_free.

mpeg_seq_hdr_free $seqHdr
bitstream_mmap_read_free $bs
bitparser_free $bp

Source code for this lesson : l6.tcl


Lesson 5 : More ByteImage | Lesson 7 : Decoding MPEG I Frames | Contents


Last Updated : 06/05/2025 04:28:20