📄 mpeg2_ps.c
字号:
if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } } sptr->frame_len = hdr.framesize; sptr->pes_buffer_on += diff; if (diff == 0 && started_new_pes) { // we might have a new PTS - but it's not here } else { sptr->frame_ts = sptr->next_pes_ts; sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0; } while (sptr->pes_buffer_size - sptr->pes_buffer_on < sptr->frame_len) {#if 0 printf("don't have enough - on %u size %u %u %u\n", sptr->pes_buffer_on, sptr->pes_buffer_size, sptr->pes_buffer_size - sptr->pes_buffer_on, sptr->frame_len);#endif if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } } sptr->have_frame_loaded = 1; return 1;}static Bool mpeg2ps_stream_find_mp3_frame (mpeg2ps_stream_t *sptr){ u32 diff, hdr; Bool started_new_pes = 0; 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 ((hdr=gf_mp3_get_next_header_mem((char*)sptr->pes_buffer + sptr->pes_buffer_on, sptr->pes_buffer_size - sptr->pes_buffer_on, &diff) ) == 0) { // don't have frame if (sptr->pes_buffer_size > 3) { if (sptr->pes_buffer_on != sptr->pes_buffer_size) { sptr->pes_buffer_on = sptr->pes_buffer_size - 3; } started_new_pes = 1; // we have left over bytes... } else { sptr->pes_buffer_on = sptr->pes_buffer_size; } if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } } // have frame. sptr->frame_len = gf_mp3_frame_size(hdr); sptr->pes_buffer_on += diff; if (diff == 0 && started_new_pes) { } else { sptr->frame_ts = sptr->next_pes_ts; sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0; } while (sptr->pes_buffer_size - sptr->pes_buffer_on < sptr->frame_len) {#if 0 printf("don't have enough - on %u size %u %u %u\n", sptr->pes_buffer_on, sptr->pes_buffer_size, sptr->pes_buffer_size - sptr->pes_buffer_on, sptr->frame_len);#endif if (mpeg2ps_stream_read_next_pes_buffer(sptr) == 0) { return 0; } } sptr->have_frame_loaded = 1; return 1;}/* * mpeg2ps_stream_read_frame. read the correct frame based on stream type. * advance_pointers is 0 when we want to use the data */static Bool mpeg2ps_stream_read_frame (mpeg2ps_stream_t *sptr, u8 **buffer, u32 *buflen, Bool advance_pointers){ // Bool done = 0; if (sptr->is_video) { if (mpeg2ps_stream_find_mpeg_video_frame(sptr)) { *buffer = sptr->pes_buffer + sptr->pes_buffer_on; *buflen = sptr->frame_len; if (advance_pointers) { sptr->pes_buffer_on += sptr->frame_len; } return 1; } return 0; } else if (sptr->m_stream_id == 0xbd) { // would need to handle LPCM here if (mpeg2ps_stream_find_ac3_frame(sptr)) { *buffer = sptr->pes_buffer + sptr->pes_buffer_on; *buflen = sptr->frame_len; if (advance_pointers) sptr->pes_buffer_on += sptr->frame_len; return 1; } return 0; } else if (mpeg2ps_stream_find_mp3_frame(sptr)) { *buffer = sptr->pes_buffer + sptr->pes_buffer_on; *buflen = sptr->frame_len; if (advance_pointers) sptr->pes_buffer_on += sptr->frame_len; return 1; } return 0;}/* * get_info_from_frame - we have a frame, get the info from it. */static void get_info_from_frame (mpeg2ps_stream_t *sptr, u8 *buffer, u32 buflen){ if (sptr->is_video) { if (MPEG12_ParseSeqHdr(buffer, buflen, &sptr->have_mpeg2, &sptr->h, &sptr->w, &sptr->frame_rate, &sptr->bit_rate, &sptr->par) < 0) { sptr->m_stream_id = 0; sptr->m_fd = FDNULL; } sptr->ticks_per_frame = (u64)(90000.0 / sptr->frame_rate); return; } if (sptr->m_stream_id >= 0xc0) { // mpeg audio u32 hdr = GF_4CC(buffer[0],buffer[1],buffer[2],buffer[3]); sptr->channels = gf_mp3_num_channels(hdr); sptr->freq = gf_mp3_sampling_rate(hdr); sptr->samples_per_frame = gf_mp3_window_size(hdr); sptr->bitrate = gf_mp3_bit_rate(hdr) * 1000; // give bps, not kbps sptr->layer = gf_mp3_layer(hdr); } else if (sptr->m_stream_id == 0xbd) { if (sptr->m_substream_id >= 0xa0) { // PCM - ??? } else if (sptr->m_substream_id >= 0x80) { u32 pos; GF_AC3Header hdr; gf_ac3_parser(buffer, buflen, &pos, &hdr); sptr->bitrate = hdr.bitrate; sptr->freq = hdr.sample_rate; sptr->channels = hdr.channels; sptr->samples_per_frame = 256 * 6; } else { return; } } else { return; }}/* * clear_stream_buffer - called when we seek to clear out any data in * the buffers */static void clear_stream_buffer (mpeg2ps_stream_t *sptr){ sptr->pes_buffer_on = sptr->pes_buffer_size = 0; sptr->frame_len = 0; sptr->have_frame_loaded = 0; sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = 0; sptr->frame_ts.have_dts = sptr->frame_ts.have_pts = 0;}/* * convert_to_msec - convert ts (at 90000) to msec, based on base_ts and * frames_since_last_ts. */static u64 convert_ts (mpeg2ps_stream_t *sptr, mpeg2ps_ts_type_t ts_type, u64 ts, u64 base_ts, u32 frames_since_ts){ u64 ret, calc; ret = ts - base_ts; if (sptr->is_video) { // video ret += frames_since_ts * sptr->ticks_per_frame; } else { // audio calc = (frames_since_ts * 90000 * sptr->samples_per_frame) / sptr->freq; ret += calc; } if (ts_type == TS_MSEC) ret /= (u64) (90); // * 1000 / 90000 return ret;}/* * find_stream_from_id - given the stream, get the sptr. * only used in inital set up, really. APIs use index into * video_streams and audio_streams arrays. */static mpeg2ps_stream_t *find_stream_from_id (mpeg2ps_t *ps, u8 stream_id, u8 substream){ u8 ix; if (stream_id >= 0xe0) { for (ix = 0; ix < ps->video_cnt; ix++) { if (ps->video_streams[ix]->m_stream_id == stream_id) { return ps->video_streams[ix]; } } } else { for (ix = 0; ix < ps->audio_cnt; ix++) { if (ps->audio_streams[ix]->m_stream_id == stream_id && (stream_id != 0xbd || substream == ps->audio_streams[ix]->m_substream_id)) { return ps->audio_streams[ix]; } } } return NULL;}/* * add_stream - add a new stream */static Bool add_stream (mpeg2ps_t *ps, u8 stream_id, u8 substream, s64 first_loc, mpeg2ps_ts_t *ts){ mpeg2ps_stream_t *sptr; sptr = find_stream_from_id(ps, stream_id, substream); if (sptr != NULL) return 0; // need to add sptr = mpeg2ps_stream_create(stream_id, substream); sptr->first_pes_loc = first_loc; if (ts == NULL || (ts->have_dts == 0 && ts->have_pts == 0)) { sptr->first_pes_has_dts = 0; } else { sptr->start_dts = ts->have_dts ? ts->dts : ts->pts; sptr->first_pes_has_dts = 1; } if (sptr->is_video) { // can't be more than 16 - e0 to ef... ps->video_streams[ps->video_cnt] = sptr; ps->video_cnt++; } else { if (ps->audio_cnt >= 32) { mpeg2ps_stream_destroy(sptr); return 0; } ps->audio_streams[ps->audio_cnt] = sptr; ps->audio_cnt++; } return 1;}static void check_fd_for_stream (mpeg2ps_t *ps, mpeg2ps_stream_t *sptr){ if (sptr->m_fd != FDNULL) return; sptr->m_fd = file_open(ps->filename);}/* * advance_frame - when we're reading frames, this indicates that we're * done. We will call this when we read a frame, but not when we * seek. It allows us to leave the last frame we're seeking in the * buffer */static void advance_frame (mpeg2ps_stream_t *sptr){ sptr->pes_buffer_on += sptr->frame_len; sptr->have_frame_loaded = 0; if (sptr->frame_ts.have_dts || sptr->frame_ts.have_pts) { if (sptr->frame_ts.have_dts) sptr->last_ts = sptr->frame_ts.dts; else sptr->last_ts = sptr->frame_ts.pts; sptr->frames_since_last_ts = 0; } else { sptr->frames_since_last_ts++; }}/* * get_info_for_all_streams - loop through found streams - read an * figure out the info */static void get_info_for_all_streams (mpeg2ps_t *ps){ u8 stream_ix, max_ix, av; mpeg2ps_stream_t *sptr; u8 *buffer; u32 buflen; file_seek_to(ps->fd, 0); // av will be 0 for video streams, 1 for audio streams // av is just so I don't have to dup a lot of code that does the // same thing. for (av = 0; av < 2; av++) { if (av == 0) max_ix = ps->video_cnt; else max_ix = ps->audio_cnt; for (stream_ix = 0; stream_ix < max_ix; stream_ix++) { if (av == 0) sptr = ps->video_streams[stream_ix]; else sptr = ps->audio_streams[stream_ix]; // we don't open a seperate file descriptor yet (only when they // start reading or seeking). Use the one from the ps. sptr->m_fd = ps->fd; // for now clear_stream_buffer(sptr); if (mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, 0) == 0) { sptr->m_stream_id = 0; sptr->m_fd = FDNULL; continue; } get_info_from_frame(sptr, buffer, buflen); // here - if (sptr->first_pes_has_dts == 0) should be processed if (sptr->first_pes_has_dts == 0) { u32 frames_from_beg = 0; Bool have_frame; do { advance_frame(sptr); have_frame = mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, 0); frames_from_beg++; } while (have_frame && sptr->frame_ts.have_dts == 0 && sptr->frame_ts.have_pts == 0 && frames_from_beg < 1000); if (have_frame == 0 || (sptr->frame_ts.have_dts == 0 && sptr->frame_ts.have_pts == 0)) { } else { sptr->start_dts = sptr->frame_ts.have_dts ? sptr->frame_ts.dts : sptr->frame_ts.pts; if (sptr->is_video) { sptr->start_dts -= frames_from_beg * sptr->ticks_per_frame; } else { u64 conv; conv = sptr->samples_per_frame * 90000; conv /= (u64)sptr->freq; sptr->start_dts -= conv; } } } clear_stream_buffer(sptr); sptr->m_fd = FDNULL; } }}/* * mpeg2ps_scan_file - read file, grabbing all the information that * we can out of it (what streams exist, timing, etc). */static void mpeg2ps_scan_file (mpeg2ps_t *ps){ u8 stream_id, stream_ix, substream, av_ix, max_cnt; u16 pes_len, pes_left; mpeg2ps_ts_t ts; s64 loc, first_video_loc = 0, first_audio_loc = 0; s64 check, orig_check; mpeg2ps_stream_t *sptr; Bool valid_stream; u8 *buffer; u32 buflen; Bool have_ts; ps->end_loc = file_size(ps->fd); orig_check = check = MAX(ps->end_loc / 50, 200 * 1024); /* * This part reads and finds the streams. We check up until we * find audio and video plus a little, with a max of either 200K or * the file size / 50 */ loc = 0; while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len) && loc < check) { pes_left = pes_len; if (stream_id >= 0xbd && stream_id < 0xf0) { loc = file_location(ps->fd) - 6; if (read_pes_header_data(ps->fd, pes_len, &pes_left, &have_ts, &ts) == 0) { return; } valid_stream = 0; substream = 0; if (stream_id == 0xbd) { if (file_read_bytes(ps->fd, &substream, 1) == 0) { return; } pes_left--; // remove byte we just read if ((substream >= 0x80 && substream < 0x90) || (substream >= 0xa0 && substream < 0xb0)){ valid_stream = 1; } } else if (stream_id >= 0xc0 && stream_id <= 0xef) { // audio and video valid_stream = 1; } if (valid_stream) { if (add_stream(ps, stream_id, substream, loc, &ts)) { // added if (stream_id >= 0xe0) { if (ps->video_cnt == 1) { first_video_loc = loc; } } else if (ps->audio_cnt == 1) { first_audio_loc = loc; } if (ps->audio_cnt > 0 && ps->video_cnt > 0) { s64 diff; if (first_audio_loc > first_video_loc) diff = first_audio_loc - first_video_loc; else diff = first_video_loc - first_audio_loc; diff *= 2; diff += first_video_loc; if (diff < check) { check = diff; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -