📄 mpeg2_ps.c
字号:
} } file_skip_bytes(ps->fd, pes_left); } if (ps->video_cnt == 0 && ps->audio_cnt == 0) { return; } /* * Now, we go to close to the end, and try to find the last * dts that we can */ // printf("to end "X64"\n", end - orig_check); file_seek_to(ps->fd, ps->end_loc - orig_check); while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len)) { loc = file_location(ps->fd) - 6; if (stream_id == 0xbd || (stream_id >= 0xc0 && stream_id < 0xf0)) { if (read_pes_header_data(ps->fd, pes_len, &pes_left, &have_ts, &ts) == 0) { return; } 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))) { file_skip_bytes(ps->fd, pes_left); continue; } } else { substream = 0; } sptr = find_stream_from_id(ps, stream_id, substream); if (sptr == NULL) { add_stream(ps, stream_id, substream, 0, NULL); sptr = find_stream_from_id(ps, stream_id, substream); } if (sptr != NULL && have_ts) { sptr->end_dts = ts.have_dts ? ts.dts : ts.pts; sptr->end_dts_loc = loc; }#if 0 printf("loc "X64" stream %x %x", loc, stream_id, substream); if (ts.have_pts) printf(" pts "U64, ts.pts); if (ts.have_dts) printf(" dts "U64, ts.dts); printf("\n");#endif file_skip_bytes(ps->fd, pes_left); } } /* * Now, get the info for all streams, so we can use it again * we could do this before the above, I suppose */ get_info_for_all_streams(ps); ps->first_dts = (u64) -1; /* * we need to find the earliest start pts - we use that to calc * the rest of the timing, so we're 0 based. */ for (av_ix = 0; av_ix < 2; av_ix++) { if (av_ix == 0) max_cnt = ps->video_cnt; else max_cnt = ps->audio_cnt; for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) { sptr = av_ix == 0 ? ps->video_streams[stream_ix] : ps->audio_streams[stream_ix]; if (sptr != NULL && sptr->start_dts < ps->first_dts) { ps->first_dts = sptr->start_dts; } } } /* * Now, for each thread, we'll start at the last pts location, and * read the number of frames. This will give us a max time */ for (av_ix = 0; av_ix < 2; av_ix++) { if (av_ix == 0) max_cnt = ps->video_cnt; else max_cnt = ps->audio_cnt; for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) { u32 frame_cnt_since_last; sptr = av_ix == 0 ? ps->video_streams[stream_ix] : ps->audio_streams[stream_ix]; // pick up here - find the final time... if (sptr->end_dts_loc != 0) { file_seek_to(ps->fd, sptr->end_dts_loc); sptr->m_fd = ps->fd; frame_cnt_since_last = 0; clear_stream_buffer(sptr); while (mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, 1)) { frame_cnt_since_last++; } sptr->m_fd = FDNULL; clear_stream_buffer(sptr); ps->max_time = MAX(ps->max_time, convert_ts(sptr, TS_MSEC, sptr->end_dts, ps->first_dts, frame_cnt_since_last)); } } } ps->max_dts = (ps->max_time * 90) + ps->first_dts; file_seek_to(ps->fd, 0);}/************************************************************************* * API routines *************************************************************************/u64 mpeg2ps_get_max_time_msec (mpeg2ps_t *ps) { return ps->max_time;}u32 mpeg2ps_get_video_stream_count (mpeg2ps_t *ps){ return ps->video_cnt;}#define NUM_ELEMENTS_IN_ARRAY(name) ((sizeof((name))) / (sizeof(*(name))))// routine to check stream number passed.static Bool invalid_video_streamno (mpeg2ps_t *ps, u32 streamno){ if (streamno >= NUM_ELEMENTS_IN_ARRAY(ps->video_streams)) return 1; if (ps->video_streams[streamno] == NULL) return 1; return 0;}const char *mpeg2ps_get_video_stream_name (mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) { return 0; } if (ps->video_streams[streamno]->have_mpeg2) { return "Mpeg-2"; } return "Mpeg-1";}mpeg2ps_video_type_t mpeg2ps_get_video_stream_type (mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) { return MPEG_VIDEO_UNKNOWN; } return ps->video_streams[streamno]->have_mpeg2 ? MPEG_VIDEO_MPEG2 : MPEG_VIDEO_MPEG1;}u32 mpeg2ps_get_video_stream_width (mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) { return 0; } return ps->video_streams[streamno]->w;}u32 mpeg2ps_get_video_stream_height (mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) { return 0; } return ps->video_streams[streamno]->h;}u32 mpeg2ps_get_video_stream_aspect_ratio (mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) { return 0; } return ps->video_streams[streamno]->par;}Double mpeg2ps_get_video_stream_bitrate (mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) { return 0; } return ps->video_streams[streamno]->bit_rate;}Double mpeg2ps_get_video_stream_framerate (mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) { return 0; } return ps->video_streams[streamno]->frame_rate;}static Bool invalid_audio_streamno (mpeg2ps_t *ps, u32 streamno){ if (streamno >= NUM_ELEMENTS_IN_ARRAY(ps->audio_streams)) return 1; if (ps->audio_streams[streamno] == NULL) return 1; return 0;}u32 mpeg2ps_get_audio_stream_count (mpeg2ps_t *ps){ return ps->audio_cnt;}const char *mpeg2ps_get_audio_stream_name (mpeg2ps_t *ps, u32 streamno){ if (invalid_audio_streamno(ps, streamno)) { return "none"; } if (ps->audio_streams[streamno]->m_stream_id >= 0xc0) { switch (ps->audio_streams[streamno]->layer) { case 1: return "MP1"; case 2: return "MP2"; case 3: return "MP3"; } return "unknown mpeg layer"; } if (ps->audio_streams[streamno]->m_substream_id >= 0x80 && ps->audio_streams[streamno]->m_substream_id < 0x90) return "AC3"; return "LPCM";}mpeg2ps_audio_type_t mpeg2ps_get_audio_stream_type (mpeg2ps_t *ps, u32 streamno){ if (invalid_audio_streamno(ps, streamno)) { return MPEG_AUDIO_UNKNOWN; } if (ps->audio_streams[streamno]->m_stream_id >= 0xc0) { return MPEG_AUDIO_MPEG; } if (ps->audio_streams[streamno]->m_substream_id >= 0x80 && ps->audio_streams[streamno]->m_substream_id < 0x90) return MPEG_AUDIO_AC3; return MPEG_AUDIO_LPCM;}u32 mpeg2ps_get_audio_stream_sample_freq (mpeg2ps_t *ps, u32 streamno){ if (invalid_audio_streamno(ps, streamno)) { return 0; } return ps->audio_streams[streamno]->freq;}u32 mpeg2ps_get_audio_stream_channels (mpeg2ps_t *ps, u32 streamno){ if (invalid_audio_streamno(ps, streamno)) { return 0; } return ps->audio_streams[streamno]->channels;}u32 mpeg2ps_get_audio_stream_bitrate (mpeg2ps_t *ps, u32 streamno){ if (invalid_audio_streamno(ps, streamno)) { return 0; } return ps->audio_streams[streamno]->bitrate;}mpeg2ps_t *mpeg2ps_init (const char *filename){ mpeg2ps_t *ps; GF_SAFEALLOC(ps, mpeg2ps_t); if (ps == NULL) { return NULL; } memset(ps, 0, sizeof(*ps)); ps->fd = file_open(filename); if (file_okay(ps->fd) == 0) { free(ps); return NULL; } ps->filename = strdup(filename); mpeg2ps_scan_file(ps); if (ps->video_cnt == 0 && ps->audio_cnt == 0) { mpeg2ps_close(ps); return NULL; } return ps;}void mpeg2ps_close (mpeg2ps_t *ps){ u32 ix; if (ps == NULL) return; for (ix = 0; ix < ps->video_cnt; ix++) { mpeg2ps_stream_destroy(ps->video_streams[ix]); ps->video_streams[ix] = NULL; } for (ix = 0; ix < ps->audio_cnt; ix++) { mpeg2ps_stream_destroy(ps->audio_streams[ix]); ps->audio_streams[ix] = NULL; } if (ps->filename) free(ps->filename); if (ps->fd) file_close(ps->fd); free(ps);}/* * check_fd_for_stream will make sure we have a fd for the stream we're * trying to read - we use a different fd for each stream *//* * stream_convert_frame_ts_to_msec - given a "read" frame, we'll * calculate the msec and freq timestamps. This can be called more * than 1 time, if needed, without changing any variables, such as * frames_since_last_ts, which gets updated in advance_frame */static u64 stream_convert_frame_ts_to_msec (mpeg2ps_stream_t *sptr, mpeg2ps_ts_type_t ts_type, u64 base_dts, u32 *freq_ts){ u64 calc_ts; u32 frames_since_last = 0; u64 freq_conv; calc_ts = sptr->last_ts; if (sptr->frame_ts.have_dts) calc_ts = sptr->frame_ts.dts; else if (sptr->frame_ts.have_pts) calc_ts = sptr->frame_ts.dts; else frames_since_last = sptr->frames_since_last_ts + 1; if (freq_ts != NULL) { freq_conv = calc_ts - base_dts; freq_conv *= sptr->freq; freq_conv /= 90000; freq_conv += frames_since_last * sptr->samples_per_frame; *freq_ts = (u32) (freq_conv & 0xffffffff); } return convert_ts(sptr, ts_type, calc_ts, base_dts, frames_since_last);}/* * mpeg2ps_get_video_frame - gets the next frame */ Bool mpeg2ps_get_video_frame(mpeg2ps_t *ps, u32 streamno, u8 **buffer, u32 *buflen, u8 *frame_type, mpeg2ps_ts_type_t ts_type, u64 *timestamp){ mpeg2ps_stream_t *sptr; if (invalid_video_streamno(ps, streamno)) return 0; sptr = ps->video_streams[streamno]; check_fd_for_stream(ps, sptr); if (sptr->have_frame_loaded == 0) { // if we don't have the frame in the buffer (like after a seek), // read the next frame if (mpeg2ps_stream_find_mpeg_video_frame(sptr) == 0) { return 0; } } *buffer = sptr->pes_buffer + sptr->pes_buffer_on; *buflen = sptr->frame_len; // determine frame type if (frame_type != NULL) { *frame_type = MPEG12_PictHdrType(sptr->pes_buffer + sptr->pict_header_offset); } // and the timestamp if (timestamp != NULL) { *timestamp = stream_convert_frame_ts_to_msec(sptr, ts_type, ps->first_dts, NULL); } // finally, indicate that we read this frame - get ready for the next one. advance_frame(sptr); return 1;}// see above comments Bool mpeg2ps_get_audio_frame(mpeg2ps_t *ps, u32 streamno, u8 **buffer, u32 *buflen, mpeg2ps_ts_type_t ts_type, u32 *freq_timestamp, u64 *timestamp){ mpeg2ps_stream_t *sptr; u64 ts; if (invalid_audio_streamno(ps, streamno)) return 0; sptr = ps->audio_streams[streamno]; check_fd_for_stream(ps, sptr); if (sptr->have_frame_loaded == 0) { if (mpeg2ps_stream_read_frame(sptr, buffer, buflen, 0) == 0) return 0; } if (timestamp != NULL || freq_timestamp != NULL) { ts = stream_convert_frame_ts_to_msec(sptr, ts_type, ps->first_dts, freq_timestamp); if (timestamp != NULL) { *timestamp = ts; } } advance_frame(sptr); return 1;}s64 mpeg2ps_get_ps_size(mpeg2ps_t *ps){ return file_size(ps->fd);}s64 mpeg2ps_get_video_pos(mpeg2ps_t *ps, u32 streamno){ if (invalid_video_streamno(ps, streamno)) return 0; return gf_f64_tell(ps->video_streams[streamno]->m_fd);}s64 mpeg2ps_get_audio_pos(mpeg2ps_t *ps, u32 streamno){ if (invalid_audio_streamno(ps, streamno)) return 0; return gf_f64_tell(ps->audio_streams[streamno]->m_fd);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -