📄 mpeg2_ps.c
字号:
} file_skip_bytes(fd, 13 - read_from_start); file_read_bytes(fd, &readbyte, 1); stuffed = readbyte & 0x7; file_skip_bytes(fd, stuffed);}/* * find_pack_start * look for the pack start code in the file - read 512 bytes at a time, * searching for that code. * Note: we may also be okay looking for >= 00 00 01 bb */static Bool find_pack_start (FILE *fd, u8 *saved, u32 len){ u8 buffer[512]; u32 buffer_on = 0, new_offset, scode; memcpy(buffer, saved, len); if (file_read_bytes(fd, buffer + len, sizeof(buffer) - len) == 0) { return 0; } while (1) { if (MPEG12_FindNextStartCode(buffer + buffer_on, sizeof(buffer) - buffer_on, &new_offset, &scode) >= 0) { buffer_on += new_offset; if (scode == MPEG2_PS_PACKSTART) { file_skip_bytes(fd, buffer_on - 512); // go back to header return 1; } buffer_on += 1; } else { len = 0; if (buffer[sizeof(buffer) - 3] == 0 && buffer[sizeof(buffer) - 2] == 0 && buffer[sizeof(buffer) - 1] == 1) { buffer[0] = 0; buffer[1] = 0; buffer[2] = 1; len = 3; } else if (*(u16 *)(buffer + sizeof(buffer) - 2) == 0) { buffer[0] = 0; buffer[1] = 0; len = 2; } else if (buffer[sizeof(buffer) - 1] == 0) { buffer[0] = 0; len = 1; } if (file_read_bytes(fd, buffer + len, sizeof(buffer) - len) == 0) { return 0; } buffer_on = 0; } } return 0;}/* * copy_bytes_to_pes_buffer - read pes_len bytes into the buffer, * adjusting it if we need it */static void copy_bytes_to_pes_buffer (mpeg2ps_stream_t *sptr, u16 pes_len){ u32 to_move; if (sptr->pes_buffer_size + pes_len > sptr->pes_buffer_size_max) { // if no room in the buffer, we'll move it - otherwise, just fill // note - we might want a better strategy about moving the buffer - // right now, we might be moving a number of bytes if we have a large // followed by large frame. to_move = sptr->pes_buffer_size - sptr->pes_buffer_on; memmove(sptr->pes_buffer, sptr->pes_buffer + sptr->pes_buffer_on, to_move); sptr->pes_buffer_size = to_move; sptr->pes_buffer_on = 0; //printf("moving %d bytes\n", to_move); if (to_move + pes_len > sptr->pes_buffer_size_max) { sptr->pes_buffer = (u8 *)realloc(sptr->pes_buffer, to_move + pes_len + 2048); sptr->pes_buffer_size_max = to_move + pes_len + 2048; } } file_read_bytes(sptr->m_fd, sptr->pes_buffer + sptr->pes_buffer_size, pes_len); sptr->pes_buffer_size += pes_len;#if 0 printf("copying %u bytes - on %u size %u\n", pes_len, sptr->pes_buffer_on, sptr->pes_buffer_size);#endif}/* * read_to_next_pes_header - read the file, look for the next valid * pes header. We will skip over PACK headers, but not over any of the * headers listed in 13818-1, table 2-18 - basically, anything with the * 00 00 01 and the next byte > 0xbb. * We return the pes len to read, and the "next byte" */static Bool read_to_next_pes_header (FILE *fd, u8 *stream_id, u16 *pes_len){ u32 hdr; u8 local[6]; while (1) { // read the pes header if (file_read_bytes(fd, local, 6) == 0) { return 0; } hdr = convert32(local); // if we're not a 00 00 01, read until we get the next pack start // we might want to also read until next PES - look into that. if (((hdr & MPEG2_PS_START_MASK) != MPEG2_PS_START) || (hdr < MPEG2_PS_END)) { if (find_pack_start(fd, local, 6) == 0) { return 0; } continue; } if (hdr == MPEG2_PS_PACKSTART) { // pack start code - we can skip down adv_past_pack_hdr(fd, local, 6); continue; } if (hdr == MPEG2_PS_END) { file_skip_bytes(fd, -2); continue; } // we should have a valid stream and pes_len here... *stream_id = hdr & 0xff; *pes_len = convert16(local + 4);#if 0 printf("loc: "X64" %x len %u\n", file_location(fd) - 6, local[3], *pes_len);#endif return 1; } return 0;}/* * read_pes_header_data * this should read past the pes header for the audio and video streams * it will store the timestamps if it reads them */static Bool read_pes_header_data (FILE *fd, u16 orig_pes_len, u16 *pes_left, Bool *have_ts, mpeg2ps_ts_t *ts){ u16 pes_len = orig_pes_len; u8 local[10]; u32 hdr_len; ts->have_pts = 0; ts->have_dts = 0; *have_ts = 0; if (file_read_bytes(fd, local, 1) == 0) { return 0; } pes_len--; // remove this first byte from length while (*local == 0xff) { if (file_read_bytes(fd, local, 1) == 0) { return 0; } pes_len--; if (pes_len == 0) { *pes_left = 0; return 1; } } if ((*local & 0xc0) == 0x40) { // buffer scale & size file_skip_bytes(fd, 1); if (file_read_bytes(fd, local, 1) == 0) { return 0; } pes_len -= 2; } if ((*local & 0xf0) == 0x20) { // mpeg-1 with pts if (file_read_bytes(fd, local + 1, 4) == 0) { return 0; } ts->have_pts = 1; ts->pts = ts->dts = read_pts(local); //printf("mpeg1 pts "U64"\n", ts->pts); *have_ts = 1; pes_len -= 4; } else if ((*local & 0xf0) == 0x30) { // have mpeg 1 pts and dts if (file_read_bytes(fd, local + 1, 9) == 0) { return 0; } ts->have_pts = 1; ts->have_dts = 1; *have_ts = 1; ts->pts = read_pts(local); ts->dts = read_pts(local + 5); pes_len -= 9; } else if ((*local & 0xc0) == 0x80) { // mpeg2 pes header - we're pointing at the flags field now if (file_read_bytes(fd, local + 1, 2) == 0) { return 0; } hdr_len = local[2]; pes_len -= hdr_len + 2; // first byte removed already if ((local[1] & 0xc0) == 0x80) { // just pts ts->have_pts = 1; file_read_bytes(fd, local, 5); ts->pts = ts->dts = read_pts(local); *have_ts = 1; hdr_len -= 5; } else if ((local[1] & 0xc0) == 0xc0) { // pts and dts ts->have_pts = 1; ts->have_dts = 1; *have_ts = 1; file_read_bytes(fd, local, 10); ts->pts = read_pts(local); ts->dts = read_pts(local + 5); hdr_len -= 10; } file_skip_bytes(fd, hdr_len); } else if (*local != 0xf) { file_skip_bytes(fd, pes_len); pes_len = 0; } *pes_left = pes_len; return 1;}static Bool search_for_next_pes_header (mpeg2ps_stream_t *sptr, u16 *pes_len, Bool *have_ts, s64 *found_loc){ u8 stream_id; u8 local; s64 loc; while (1) { // this will read until we find the next pes. We don't know if the // stream matches - this will read over pack headers if (read_to_next_pes_header(sptr->m_fd, &stream_id, pes_len) == 0) { return 0; } if (stream_id != sptr->m_stream_id) { file_skip_bytes(sptr->m_fd, *pes_len); continue; } loc = file_location(sptr->m_fd) - 6; // advance past header, reading pts if (read_pes_header_data(sptr->m_fd, *pes_len, pes_len, have_ts, &sptr->next_pes_ts) == 0) { return 0; } // If we're looking at a private stream, make sure that the sub-stream // matches. if (sptr->m_stream_id == 0xbd) { // ac3 or pcm file_read_bytes(sptr->m_fd, &local, 1); *pes_len -= 1; if (local != sptr->m_substream_id) { file_skip_bytes(sptr->m_fd, *pes_len); continue; // skip to the next one } *pes_len -= 3; file_skip_bytes(sptr->m_fd, 3); // 4 bytes - we don't need now... // we need more here... } if (have_ts) { mpeg2ps_record_pts(sptr, loc, &sptr->next_pes_ts); } if (found_loc != NULL) *found_loc = loc; return 1; } return 0;}/* * mpeg2ps_stream_read_next_pes_buffer - for the given stream, * go forward in the file until the next PES for the stream is read. Read * the header (pts, dts), and read the data into the pes_buffer pointer */static Bool mpeg2ps_stream_read_next_pes_buffer (mpeg2ps_stream_t *sptr){ u16 pes_len; Bool have_ts; if (search_for_next_pes_header(sptr, &pes_len, &have_ts, NULL) == 0) { return 0; } copy_bytes_to_pes_buffer(sptr, pes_len); return 1;}/*************************************************************************** * Frame reading routine. For each stream, the fd's should be different. * we will read from the pes stream, and save it in the stream's pes buffer. * This will give us raw data that we can search through for frame headers, * and the like. We shouldn't read more than we need - when we need to read, * we'll put the whole next pes buffer in the buffer * * Audio routines are of the format: * look for header * determine length * make sure length is in buffer * * Video routines * look for start header (GOP, SEQ, Picture) * look for pict header * look for next start (END, GOP, SEQ, Picture) * ***************************************************************************/#define IS_MPEG_START(a) ((a) == 0xb3 || (a) == 0x00 || (a) == 0xb8)static Bool mpeg2ps_stream_find_mpeg_video_frame (mpeg2ps_stream_t *sptr){ u32 offset, scode; Bool have_pict; Bool started_new_pes = 0; u32 start; /* * First thing - determine if we have enough bytes to read the header. * if we do, we have the correct timestamp. If not, we read the new * pes, so we'd want to use the timestamp we read. */ sptr->frame_ts = sptr->next_pes_ts; if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 4) { if (sptr->pes_buffer_size != sptr->pes_buffer_on) started_new_pes = 1; if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } } while (MPEG12_FindNextStartCode(sptr->pes_buffer + sptr->pes_buffer_on, sptr->pes_buffer_size - sptr->pes_buffer_on, &offset, &scode) < 0 || (!IS_MPEG_START(scode & 0xff))) { if (sptr->pes_buffer_size > 3) sptr->pes_buffer_on = sptr->pes_buffer_size - 3; else { sptr->pes_buffer_on = sptr->pes_buffer_size; started_new_pes = 1; } if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } } sptr->pes_buffer_on += offset; if (offset == 0 && started_new_pes) { // nothing... we've copied the timestamp already. } else { // we found the new start, but we pulled in a new pes header before // starting. So, we want to use the header that we read. sptr->frame_ts = sptr->next_pes_ts; // set timestamp after searching // clear timestamp indication sptr->next_pes_ts.have_pts = sptr->next_pes_ts.have_dts = 0; }#if 0 printf("header %x at %d\n", scode, sptr->pes_buffer_on);#endif if (scode == MPEG12_PICTURE_START_CODE) { sptr->pict_header_offset = sptr->pes_buffer_on; have_pict = 1; } else have_pict = 0; start = 4 + sptr->pes_buffer_on; while (1) { if (MPEG12_FindNextStartCode(sptr->pes_buffer + start, sptr->pes_buffer_size - start, &offset, &scode) < 0) { start = sptr->pes_buffer_size - 3; start -= sptr->pes_buffer_on; sptr->pict_header_offset -= sptr->pes_buffer_on; if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } start += sptr->pes_buffer_on; sptr->pict_header_offset += sptr->pes_buffer_on; } else {#if 0 printf("2header %x at %d\n", scode, start);#endif start += offset; if (have_pict == 0) { if (scode == MPEG12_PICTURE_START_CODE) { have_pict = 1; sptr->pict_header_offset = start; } } else { if (IS_MPEG_START(scode & 0xff) || scode == MPEG12_SEQUENCE_END_START_CODE) { sptr->frame_len = start - sptr->pes_buffer_on; sptr->have_frame_loaded = 1; return 1; } } start += 4; } } return 0;}static Bool mpeg2ps_stream_find_ac3_frame (mpeg2ps_stream_t *sptr){ u32 diff; GF_AC3Header hdr; Bool started_new_pes = 0; sptr->frame_ts = sptr->next_pes_ts; // set timestamp after searching if (sptr->pes_buffer_size <= sptr->pes_buffer_on + 6) { if (sptr->pes_buffer_size != sptr->pes_buffer_on) started_new_pes = 1; if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } } while (gf_ac3_parser(sptr->pes_buffer + sptr->pes_buffer_on, sptr->pes_buffer_size - sptr->pes_buffer_on, &diff, &hdr) <= 0) { // don't have frame if (sptr->pes_buffer_size > 6) { sptr->pes_buffer_on = sptr->pes_buffer_size - 6; started_new_pes = 1; } else { sptr->pes_buffer_on = sptr->pes_buffer_size; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -