FFmpeg Analysis of MPEG2 TS Stream decoding process [2]

Source: Internet
Author: User

FFmpeg Analysis of MPEG2 TS Stream decoding process [2]

5. Get better
Well, the previous foundation is nearly enough. It's a bit like a hand-peeled onion. Let's take a look at the aspect of MPEG ts.
Resolution Process

The code behind us is mainly concentrated in [libavformat/mpegts. C]. Grandpa Mao said: concentrated strength
Wei Jie, well, let's get started, ant's nest.

Static int mpegts_read_header (avformatcontext * s,
Avformatparameters * AP)
{
Mpegtscontext * Ts = s-> priv_data;
Byteiocontext * pb = s-> Pb;
Uint8_t Buf [1024];
Int Len;
Int64_t Pos;

......

/* Read the first 1024 bytes to get packet size */
######################################## #############################
[1] with the previous analysis of buffer Io experience, the following code is not a problem :)
######################################## #############################
Pos = url_ftell (PB );
Len = get_buffer (Pb, Buf, sizeof (BUF ));
If (Len! = Sizeof (BUF ))
Goto fail;
######################################## #############################
[2] The size of the TS package is actually known when the file format is detected. This is another detection.
Some are redundant. It is estimated that the size of the package that has been detected has not been brought before due to the decoding framework,
It can be seen that although the framework is good, it will bring more or less adverse effects.
######################################## #############################
Ts-> raw_packet_size = get_packet_size (BUF, sizeof (BUF ));
If (ts-> raw_packet_size <= 0)
Goto fail;
Ts-> stream = s;
Ts-> auto_guess = 0;

If (S-> iformat ==& mpegts_demuxer ){
/* Normal Demux */

/* First do a scaning to get all the services */
Url_fseek (Pb, POs, seek_set );
######################################## ##########################
[3]
######################################## ##########################
Mpegts_scan_sdt (TS );

######################################## ##########################
[4]
######################################## ##########################
Mpegts_set_service (TS );

######################################## ##########################
[5]
######################################## ##########################
Handle_packets (TS, S-> probesize );
/* If cocould not find service, enable auto_guess */

Ts-> auto_guess = 1;

# Ifdef debug_si
Av_log (ts-> stream, av_log_debug, "Tuning done/N ");
# Endif
S-> ctx_flags | = avfmtctx_noheader;
} Else {
......
}

Url_fseek (Pb, POs, seek_set );
Return 0;
Fail:
Return-1;
}

Here, we will briefly talk about mpegtscontext * ts. From the above, we can see that this is actually to decode different container formats.
The private data used can only be used in the corresponding file, such as mpegts. C.
The biggest advantage of modularity is that the problem is concentrated in a small limited area.
When you construct your own program, you may wish to refer to its basic idea-this kind of transformation, your subsequent code, and your subsequent
Life will be much easier.

[3] [4] actually calls the same function: mpegts_open_section_filter ()
Let's take a look at what the intention is.

Static
Mpegtsfilter * mpegts_open_section_filter (mpegtscontext * ts, unsigned int PID,
Sectioncallback * section_cb,
Void * opaque,
Int check_crc)
{
Mpegtsfilter * filter;
Mpegtssectionfilter * sec;

# Ifdef debug_si
Av_log (ts-> stream, av_log_debug, "filter: pid = 0x % x/N", pid );
# Endif
If (pid> = nb_pid_max | ts-> PIDs [pid])
Return NULL;
Filter = av_mallocz (sizeof (mpegtsfilter ));
If (! Filter)
Return NULL;
Ts-> PIDs [pid] = filter;
Filter-> type = mpegts_section;
Filter-> pid = PID;
Filter-> last_cc =-1;
SEC = & filter-> U. section_filter;
Sec-> section_cb = section_cb;
Sec-> opaque = opaque;
Sec-> section_buf = av_malloc (max_section_size );
Sec-> check_crc = check_crc;
If (! Sec-> section_buf ){
Av_free (filter );
Return NULL;
}
Return filter;
}

To fully understand this part of code, we need to analyze the author's definition of the data structure:
In sequence:

Struct mpegtscontext;
|
V
Struct mpegtsfilter;
|
V
+ --------------- +
|
V v
Mpegtspesfilter mpegtssectionfilter

In fact, it is very simple, that is, struct mpegtscontext; there are nb_pid_max (8192) ts filters, and each
Struct mpegtsfilter may be the filter of PES or section.

Let's first explain why it is 8192. In the previous analysis:
Given the syntax structure of TS:
Syntax No. of BITs mnemonic
Transport_packet (){
Sync_byte 8 bslbf
Transport_error_indicator 1 bslbf
Payload_unit_start_indicator 1 bslbf
Transport_priority 1 bslbf
PID 13 uimsbf
Transport_scrambling_control 2 bslbf
Adaptation_field_control 2 bslbf
Continuity_counter 4 uimsbf
If (adaptation_field_control = '10'
| Adaptation_field_control = '11 '){
Adaptation_field ()
}
If (adaptation_field_control = '01'
| Adaptation_field_control = '11 '){
For (I = 0; I <n; I ++ ){
Data_byte 8 bslbf
}
}
}

8192 is the maximum number of 2 ^ 13 = 8192 (PID), and why is there a distinction between PES and section, see
ISO/IEC-13818-1. I really don't like to repeat what I already have.

As you can see, [3] [4] mounts Two Section filters. In fact, in the two loads of TS, Section
It is the metadata of PES. Only the section is parsed can the PES data be further parsed.
Filter.

Two Section filters are mounted as follows:
========================================================== ======================================
PID | section name | callback
========================================================== ======================================
Sdt_pid (0x0011) | servicedescriptiontable | sdt_cb
|
Pat_pid (0x0000) | programassociationtable | pat_cb

Since callback is automatically mounted, it is naturally used in the following places. Therefore, we continue

[5] The code here is the most important part. In a simple view:
Handle_packets ()
|
+-> Read_packet ()
|
+-> Handle_packet ()
|
+-> Write_section_data ()

Read_packet () is very simple, it is to find sync_byte (0x47), and it seems that handle_packet () is what we really do.
This is the reason for attention :)

This function is very important. We paste the code for analysis:
/* Handle one TS packet */
Static void handle_packet (mpegtscontext * ts, const uint8_t * packet)
{
Avformatcontext * s = ts-> stream;
Mpegtsfilter * TSS;
Int Len, PID, CC, cc_ OK, AFC, is_start;
Const uint8_t * P, * p_end;

######################################## ##################
Obtain the PID of the package
######################################## ##################
PID = av_rb16 (packet + 1) & 0x1fff;
If (PID & discard_pid (TS, pid ))
Return;
######################################## ##################
Whether it is the beginning of PES or section (payload_unit_start_indicator)
######################################## ##################
Is_start = packet [1] & 0x40;
Tss = ts-> PIDs [pid];

######################################## ##################
Ts-> auto_guess is 0 at this time, so the following code is not considered
######################################## ##################
If (ts-> auto_guess & TSS = NULL & is_start ){
Add_pes_stream (TS, PID,-1, 0 );
Tss = ts-> PIDs [pid];
}
If (! Tss)
Return;

######################################## ##################
The Code clearly states that, although checked, the results of the check are not used.
######################################## ##################
/* Continuity check (currently not used )*/
Cc = (packet [3] & 0xf );
Cc_ OK = (TSS-> last_cc <0) | (TSS-> last_cc + 1) & 0x0f) = cc ));
Tss-> last_cc = cc;

######################################## ##################
Jump to adaptation_field_control
######################################## ##################
/* Skip adaptation field */
AFC = (packet [3]> 4) & 3;
P = packet + 4;
If (AFC = 0)/* Reserved value */
Return;
If (AFC = 2)/* adaptation field only */
Return;
If (AFC = 3 ){
/* Skip adapation field */
P + = P [0] + 1;
}

######################################## ##################
P is close to the valid load in the TS package.
######################################## ##################
/* If past the end of packet, ignore */
P_end = packet + ts_packet_size;
If (P> = p_end)
Return;

Ts-> pos47 = url_ftell (ts-> stream-> Pb) % ts-> raw_packet_size;

If (TSS-> type = mpegts_section ){
If (is_start ){
######################################## #####################
For section, the first byte is Pointer field. If this field is 0,
It indicates that the end part of a section is followed by the beginning of the section. Otherwise, it is the end part of a section.
The beginning of another section. Therefore, the process here is actually composed of two values: is_start
(Payload_unit_start_indicator) and Len (pointer field) are determined together.
######################################## #####################
/* Pointer field present */
Len = * P ++;
If (p + Len> p_end)
Return;
If (LEN & cc_ OK ){
######################################## ################
1). is_start = 1
Len> 0
The load part consists of the end part of section A and the start part of section B.
End write
######################################## ################
/* Write remaining section bytes */
Write_section_data (S, TSS,
P, Len, 0 );
/* Check whether filter has been closed */
If (! Ts-> PIDs [pid])
Return;
}
P + = Len;
If (P <p_end ){
######################################## ################
2). is_start = 1
Len> 0
The load part consists of the end part of section A and the start part of section B.
Start write
Or:
3 ).
Is_start = 1
Len = 0
The load part is only the start part of a section and is written
######################################## ################
Write_section_data (S, TSS,
P, p_end-P, 1 );
}
} Else {
If (cc_ OK ){
######################################## ################
4). is_start = 0
The load part is only the middle part of a section and is written
######################################## ################
Write_section_data (S, TSS,
P, p_end-P, 0 );
}
}
} Else {
######################################## ##################
If it is of the PES type, call its callback directly, but apparently, only the section Section
PES can be parsed only after resolution is complete.
######################################## ##################
Tss-> U. pes_filter.pes_cb (TSS,
P, p_end-P, is_start );
}
}

The write_section_data () function repeatedly collects data in the buffer to guide the reorganization of related sections.
And then call the two previously registered section_cb:

Next we will analyze the two previously linked section_cb, to be continued ......

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.