/* * Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd * * SPDX-License-Identifier: Apache-2.0 * * Author: * Desc: mpegts file demuxer */ #define LOG_TAG "mpegts" #include "mpegts.h" #include "aic_parser.h" #include "aic_stream.h" #include "aic_tag.h" #include "avi.h" #include "mpegts_audio.h" #include "mpp_list.h" #include "mpp_log.h" #include "mpp_mem.h" #include #include #include #include #define TS_FEC_PACKET_SIZE 204 #define TS_DVHS_PACKET_SIZE 192 #define TS_PACKET_SIZE 188 #define TS_MAX_PACKET_SIZE 204 #define TS_TIMESTAMP_BASE_HZ 90000 #define NB_PID_MAX 8192 #define USUAL_SECTION_SIZE 1024 /* except EIT which is limited to 4096 */ #define MAX_SECTION_SIZE 4096 /* pids */ #define PAT_PID 0x0000 /* Program Association Table */ #define CAT_PID 0x0001 /* Conditional Access Table */ #define TSDT_PID 0x0002 /* Transport Stream Description Table */ #define IPMP_PID 0x0003 /* PID from 0x0004 to 0x000F are reserved */ #define NIT_PID 0x0010 /* Network Information Table */ #define SDT_PID 0x0011 /* Service Description Table */ #define BAT_PID 0x0011 /* Bouquet Association Table */ #define EIT_PID 0x0012 /* Event Information Table */ #define RST_PID 0x0013 /* Running Status Table */ #define TDT_PID 0x0014 /* Time and Date Table */ #define TOT_PID 0x0014 #define NET_SYNC_PID 0x0015 #define RNT_PID 0x0016 /* RAR Notification Table */ /* PID from 0x0017 to 0x001B are reserved for future use */ /* PID value 0x001C allocated to link-local inband signalling shall not be * used on any broadcast signals. It shall only be used between devices in a * controlled environment. */ #define LINK_LOCAL_PID 0x001C #define MEASUREMENT_PID 0x001D #define DIT_PID 0x001E /* Discontinuity Information Table */ #define SIT_PID 0x001F /* Selection Information Table */ /* PID from 0x0020 to 0x1FFA may be assigned as needed to PMT, elementary * streams and other data tables */ #define FIRST_OTHER_PID 0x0020 #define LAST_OTHER_PID 0x1FFA /* PID 0x1FFB is used by DigiCipher 2/ATSC MGT metadata */ /* PID from 0x1FFC to 0x1FFE may be assigned as needed to PMT, elementary * streams and other data tables */ #define NULL_PID 0x1FFF /* Null packet (used for fixed bandwidth padding) */ /* m2ts pids */ #define M2TS_PMT_PID 0x0100 #define M2TS_PCR_PID 0x1001 #define M2TS_VIDEO_PID 0x1011 #define M2TS_AUDIO_START_PID 0x1100 #define M2TS_PGSSUB_START_PID 0x1200 #define M2TS_TEXTSUB_PID 0x1800 #define M2TS_SECONDARY_AUDIO_START_PID 0x1A00 #define M2TS_SECONDARY_VIDEO_START_PID 0x1B00 /* table ids */ #define PAT_TID 0x00 /* Program Association section */ #define CAT_TID 0x01 /* Conditional Access section */ #define PMT_TID 0x02 /* Program Map section */ #define TSDT_TID 0x03 /* Transport Stream Description section */ /* TID from 0x04 to 0x3F are reserved */ #define M4OD_TID 0x05 #define NIT_TID 0x40 /* Network Information section - actual network */ #define ONIT_TID 0x41 /* Network Information section - other network */ #define SDT_TID 0x42 /* Service Description section - actual TS */ /* TID from 0x43 to 0x45 are reserved for future use */ #define OSDT_TID 0x46 /* Service Descrition section - other TS */ /* TID from 0x47 to 0x49 are reserved for future use */ #define BAT_TID 0x4A /* Bouquet Association section */ #define UNT_TID 0x4B /* Update Notification Table section */ #define DFI_TID 0x4C /* Downloadable Font Info section */ /* TID 0x4D is reserved for future use */ #define EIT_TID 0x4E /* Event Information section - actual TS */ #define OEIT_TID 0x4F /* Event Information section - other TS */ #define EITS_START_TID 0x50 /* Event Information section schedule - actual TS */ #define EITS_END_TID 0x5F /* Event Information section schedule - actual TS */ #define OEITS_START_TID 0x60 /* Event Information section schedule - other TS */ #define OEITS_END_TID 0x6F /* Event Information section schedule - other TS */ #define TDT_TID 0x70 /* Time Date section */ #define RST_TID 0x71 /* Running Status section */ #define ST_TID 0x72 /* Stuffing section */ #define TOT_TID 0x73 /* Time Offset section */ #define AIT_TID 0x74 /* Application Inforamtion section */ #define CT_TID 0x75 /* Container section */ #define RCT_TID 0x76 /* Related Content section */ #define CIT_TID 0x77 /* Content Identifier section */ #define MPE_FEC_TID 0x78 /* MPE-FEC section */ #define RPNT_TID 0x79 /* Resolution Provider Notification section */ #define MPE_IFEC_TID 0x7A /* MPE-IFEC section */ #define PROTMT_TID 0x7B /* Protection Message section */ /* TID from 0x7C to 0x7D are reserved for future use */ #define DIT_TID 0x7E /* Discontinuity Information section */ #define SIT_TID 0x7F /* Selection Information section */ /* TID from 0x80 to 0xFE are user defined */ /* TID 0xFF is reserved */ #define STREAM_TYPE_VIDEO_MPEG1 0x01 #define STREAM_TYPE_VIDEO_MPEG2 0x02 #define STREAM_TYPE_AUDIO_MPEG1 0x03 #define STREAM_TYPE_AUDIO_MPEG2 0x04 #define STREAM_TYPE_PRIVATE_SECTION 0x05 #define STREAM_TYPE_PRIVATE_DATA 0x06 #define STREAM_TYPE_AUDIO_AAC 0x0f #define STREAM_TYPE_AUDIO_AAC_LATM 0x11 #define STREAM_TYPE_VIDEO_MPEG4 0x10 #define STREAM_TYPE_METADATA 0x15 #define STREAM_TYPE_VIDEO_H264 0x1b #define STREAM_TYPE_VIDEO_HEVC 0x24 #define STREAM_TYPE_VIDEO_CAVS 0x42 #define STREAM_TYPE_VIDEO_VC1 0xea #define STREAM_TYPE_VIDEO_DIRAC 0xd1 #define STREAM_TYPE_AUDIO_AC3 0x81 #define STREAM_TYPE_AUDIO_DTS 0x82 #define STREAM_TYPE_AUDIO_TRUEHD 0x83 #define STREAM_TYPE_AUDIO_EAC3 0x87 /* maximum size in which we look for synchronization if * synchronization is lost */ #define MAX_RESYNC_SIZE 65536 #define MAX_PES_PAYLOAD 200 * 1024 #define MAX_MP4_DESCR_COUNT 16 /* enough for PES header + length */ #define PES_START_SIZE 6 #define PES_HEADER_SIZE 9 #define MAX_PES_HEADER_SIZE (9 + 255) #define PES_H264_NAL_AUD_SIZE 6 #define MAX_PIDS_PER_PROGRAM 64 #define PROBE_PACKET_MAX_BUF 8192 #define PROBE_PACKET_MARGIN 5 #define MPEGTS_INPUT_BUFFER_PADDING_SIZE 64 enum MPEGTS_FILTER_TYPE { MPEGTS_PES, MPEGTS_SECTION, MPEGTS_PCR, }; enum MPEGTS_TS_STATE { MPEGTS_HEADER = 0, MPEGTS_PESHEADER, MPEGTS_PESHEADER_FILL, MPEGTS_PAYLOAD, MPEGTS_SKIP, }; typedef struct mpegts_ts_filter mpegts_ts_filter; typedef struct mpegts_pes_context mpegts_pes_context; typedef int mpegts_pes_callback(mpegts_ts_filter *f, const uint8_t *buf, int len, int is_start, int64_t pos); typedef void mpegts_section_callback(mpegts_ts_filter *f, const uint8_t *buf, int len); typedef struct mpegts_pes_filter { mpegts_pes_callback *pes_cb; void *opaque; } mpegts_pes_filter; typedef struct mpegts_section_filter { int section_index; int section_h_size; int last_ver; unsigned crc; unsigned last_crc; uint8_t *section_buf; unsigned int check_crc : 1; unsigned int end_of_section_reached : 1; mpegts_section_callback *section_cb; void *opaque; } mpegts_section_filter; struct mpegts_ts_filter { int pid; int es_id; int last_cc; /* last cc code (-1 if first packet) */ int64_t last_pcr; int discard; enum MPEGTS_FILTER_TYPE type; union { mpegts_pes_filter pes_filter; mpegts_section_filter section_filter; } u; }; typedef struct mpegts_section_header { uint8_t tid; uint16_t id; uint8_t version; uint8_t sec_num; uint8_t last_sec_num; } mpegts_section_header; typedef struct mpegts_context { /* user data */ struct aic_mpegts_parser *parser; /** raw packet size, including FEC if present */ int raw_packet_size; int64_t pos47_full; /** if true, all pids are analyzed to find streams */ int auto_guess; /* data needed to handle file based ts */ /** stop parsing loop */ int stop_parse; /** packet temp Audio/Video data */ struct aic_parser_packet pkt; enum CodecID cur_codec_id; uint8_t first_pkt[TS_PACKET_SIZE]; int first_pkt_size; mpegts_pes_context *last_pes; uint32_t read_offset; uint32_t no_need_peek; uint32_t find_first_audio; uint32_t has_audio; /** to detect seek */ int64_t last_pos; int skip_changes; int skip_pmt; int resync_size; int merge_pmt_versions; int id; /** filters for various streams specified by PMT + for the PAT and PMT */ mpegts_ts_filter *pids[NB_PID_MAX]; int current_pid; } mpegts_context; struct mpegts_pes_context { int pid; int pcr_pid; /**< if -1 then all packets containing PCR are considered */ int stream_type; struct mpegts_context *ts; struct aic_mpegts_parser *parser; struct mpegts_stream_ctx *st; enum MPEGTS_TS_STATE state; /* used to get the format */ int data_index; int flags; /**< copied to the Packet flags */ int total_size; int pes_header_size; int extended_stream_id; uint8_t stream_id; int64_t pts, dts; int64_t ts_packet_pos; /**< position of first TS packet of this PES packet */ uint8_t header[MAX_PES_HEADER_SIZE]; void *buffer; int merged_st; }; typedef struct mpegts_stream_type { uint32_t stream_type; enum aic_stream_type codec_type; enum CodecID codec_id; } mpegts_stream_type; static const mpegts_stream_type iso_types[] = { {STREAM_TYPE_AUDIO_MPEG1, MPP_MEDIA_TYPE_AUDIO, CODEC_ID_MP3}, {STREAM_TYPE_AUDIO_MPEG2, MPP_MEDIA_TYPE_AUDIO, CODEC_ID_MP3}, {STREAM_TYPE_AUDIO_AAC, MPP_MEDIA_TYPE_AUDIO, CODEC_ID_AAC}, {STREAM_TYPE_VIDEO_MPEG4, MPP_MEDIA_TYPE_VIDEO, CODEC_ID_MPEG4}, {STREAM_TYPE_VIDEO_H264, MPP_MEDIA_TYPE_VIDEO, CODEC_ID_H264}, {STREAM_TYPE_PRIVATE_DATA, MPP_MEDIA_TYPE_VIDEO, CODEC_ID_MJPEG}, {0x1c, MPP_MEDIA_TYPE_AUDIO, CODEC_ID_AAC}, {0x20, MPP_MEDIA_TYPE_VIDEO, CODEC_ID_H264}, {0x21, MPP_MEDIA_TYPE_VIDEO, CODEC_ID_MJPEG}, {0}, }; static int64_t mpegts_parse_pes_pts(const uint8_t *buf) { return (int64_t)(*buf & 0x0e) << 29 | (AIC_RB16(buf + 1) >> 1) << 15 | AIC_RB16(buf + 3) >> 1; } static int mpegts_mid_pred(int a, int b, int c) { if (a > b) { if (c > b) { if (c > a) b = a; else b = c; } } else { if (b > c) { if (c > a) b = c; else b = a; } } return b; } /** * Assemble PES packets out of TS packets, and then call the "section_cb" * function when they are complete. */ static void write_section_data(mpegts_context *ts, mpegts_ts_filter *tss1, const uint8_t *buf, int buf_size, int is_start) { mpegts_section_filter *tss = &tss1->u.section_filter; uint8_t *cur_section_buf = NULL; int len, offset; if (is_start) { memcpy(tss->section_buf, buf, buf_size); tss->section_index = buf_size; tss->section_h_size = -1; tss->end_of_section_reached = 0; } else { if (tss->end_of_section_reached) return; len = MAX_SECTION_SIZE - tss->section_index; if (buf_size < len) len = buf_size; memcpy(tss->section_buf + tss->section_index, buf, len); tss->section_index += len; } offset = 0; cur_section_buf = tss->section_buf; while (cur_section_buf - tss->section_buf < MAX_SECTION_SIZE && cur_section_buf[0] != 0xff) { /* compute section length if possible */ if (tss->section_h_size == -1 && tss->section_index - offset >= 3) { len = (AIC_RB16(cur_section_buf + 1) & 0xfff) + 3; if (len > MAX_SECTION_SIZE) return; tss->section_h_size = len; } if (tss->section_h_size != -1 && tss->section_index >= offset + tss->section_h_size) { tss->end_of_section_reached = 1; tss->section_cb(tss1, cur_section_buf, tss->section_h_size); cur_section_buf += tss->section_h_size; offset += tss->section_h_size; tss->section_h_size = -1; } else { tss->section_h_size = -1; tss->end_of_section_reached = 0; break; } } } static mpegts_ts_filter *mpegts_open_filter(struct mpegts_context *ts, unsigned int pid, enum MPEGTS_FILTER_TYPE type) { mpegts_ts_filter *filter; if (pid >= NB_PID_MAX || ts->pids[pid]) return NULL; filter = mpp_alloc(sizeof(mpegts_ts_filter)); if (!filter) return NULL; memset(filter, 0, sizeof(mpegts_ts_filter)); ts->pids[pid] = filter; filter->type = type; filter->pid = pid; filter->es_id = -1; filter->last_cc = -1; filter->last_pcr = -1; return filter; } static mpegts_ts_filter *mpegts_open_section_filter(struct mpegts_context *ts, unsigned int pid, mpegts_section_callback *section_cb, void *opaque, int check_crc) { mpegts_ts_filter *filter; mpegts_section_filter *sec; if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_SECTION))) return NULL; sec = &filter->u.section_filter; sec->section_cb = section_cb; sec->opaque = opaque; sec->section_buf = mpp_alloc(MAX_SECTION_SIZE); sec->check_crc = check_crc; sec->last_ver = -1; if (!sec->section_buf) { mpp_free(filter); return NULL; } else { memset(sec->section_buf, 0, MAX_SECTION_SIZE); } return filter; } static mpegts_ts_filter *mpegts_open_pes_filter(struct mpegts_context *ts, unsigned int pid, mpegts_pes_callback *pes_cb, void *opaque) { mpegts_ts_filter *filter; mpegts_pes_filter *pes; if (!(filter = mpegts_open_filter(ts, pid, MPEGTS_PES))) return NULL; pes = &filter->u.pes_filter; pes->pes_cb = pes_cb; pes->opaque = opaque; return filter; } static void mpegts_close_filter(struct mpegts_context *ts, mpegts_ts_filter *filter) { if (filter == NULL) return; int pid = filter->pid; if (filter->type == MPEGTS_SECTION) { mpp_free(filter->u.section_filter.section_buf); filter->u.section_filter.section_buf = NULL; } else if (filter->type == MPEGTS_PES) { mpp_free(filter->u.pes_filter.opaque); } mpp_free(filter); ts->pids[pid] = NULL; } static int mpegts_analyze(const uint8_t *buf, int size, int packet_size, int probe) { int stat[TS_MAX_PACKET_SIZE]; int stat_all = 0; int i; int best_score = 0; memset(stat, 0, packet_size * sizeof(*stat)); for (i = 0; i < size - 3; i++) { if (buf[i] == 0x47) { // sync_byte int pid = AIC_RB16(buf + 1) & 0x1FFF; int asc = buf[i + 3] & 0x30; if (!probe || pid == 0x1FFF || asc) { int x = i % packet_size; stat[x]++; stat_all++; if (stat[x] > best_score) { best_score = stat[x]; } } } } return best_score - MPP_MAX(stat_all - 10 * best_score, 0) / 10; } /* autodetect fec presence */ static int get_packet_size(struct aic_mpegts_parser *s) { int score, fec_score, dvhs_score; int margin; int ret; /*init buffer to store stream for probing */ uint8_t *buf = mpp_alloc(PROBE_PACKET_MAX_BUF); if (buf == NULL) { loge("malloc probe packet buf failed"); return PARSER_NOMEM; } int buf_size = 0; while (buf_size < PROBE_PACKET_MAX_BUF) { ret = aic_stream_read(s->stream, buf + buf_size, PROBE_PACKET_MAX_BUF - buf_size); if (ret < 0) goto FAILED; buf_size += ret; score = mpegts_analyze(buf, buf_size, TS_PACKET_SIZE, 0); dvhs_score = mpegts_analyze(buf, buf_size, TS_DVHS_PACKET_SIZE, 0); fec_score = mpegts_analyze(buf, buf_size, TS_FEC_PACKET_SIZE, 0); logi("Probe: %d, score: %d, dvhs_score: %d, fec_score: %d \n", buf_size, score, dvhs_score, fec_score); margin = mpegts_mid_pred(score, fec_score, dvhs_score); if (buf_size < PROBE_PACKET_MAX_BUF) margin += PROBE_PACKET_MARGIN; /*if buffer not filled */ if (score > margin) { mpp_free(buf); return TS_PACKET_SIZE; } else if (dvhs_score > margin) { mpp_free(buf); return TS_DVHS_PACKET_SIZE; } else if (fec_score > margin) { mpp_free(buf); return TS_FEC_PACKET_SIZE; } } FAILED: mpp_free(buf); return PARSER_INVALIDDATA; } static inline int get8(const uint8_t **pp, const uint8_t *p_end) { const uint8_t *p; int c; p = *pp; if (p >= p_end) return PARSER_ERROR; c = *p++; *pp = p; return c; } static inline int get16(const uint8_t **pp, const uint8_t *p_end) { const uint8_t *p; int c; p = *pp; if (1 >= p_end - p) return PARSER_ERROR; c = AIC_RB16(p); p += 2; *pp = p; return c; } static int parse_section_header(mpegts_section_header *h, const uint8_t **pp, const uint8_t *p_end) { int val; val = get8(pp, p_end); if (val < 0) return val; h->tid = val; *pp += 2; val = get16(pp, p_end); if (val < 0) return val; h->id = val; val = get8(pp, p_end); if (val < 0) return val; h->version = (val >> 1) & 0x1f; val = get8(pp, p_end); if (val < 0) return val; h->sec_num = val; val = get8(pp, p_end); if (val < 0) return val; h->last_sec_num = val; return 0; } static int mpegts_get_pkt_codec_type(uint32_t stream_type, const mpegts_stream_type *types) { for (; types->stream_type; types++) if (stream_type == types->stream_type) { return types->codec_type; } return MPP_MEDIA_TYPE_UNKNOWN; } static int mpegts_get_pkt_codec_id(uint32_t stream_type, const mpegts_stream_type *types) { for (; types->stream_type; types++) if (stream_type == types->stream_type) { return types->codec_id; } return MPP_MEDIA_TYPE_UNKNOWN; } static void mpegts_find_stream_type(struct mpegts_stream_ctx *st, uint32_t stream_type, const mpegts_stream_type *types) { for (; types->stream_type; types++) if (stream_type == types->stream_type) { if (st->codecpar.codec_type != types->codec_type || st->codecpar.codec_id != types->codec_id) { st->codecpar.codec_type = types->codec_type; st->codecpar.codec_id = types->codec_id; } return; } } static struct mpegts_stream_ctx *mpegts_new_stream(struct aic_mpegts_parser *s) { struct mpegts_stream_ctx *sc; sc = (struct mpegts_stream_ctx *)mpp_alloc(sizeof(struct mpegts_stream_ctx)); if (sc == NULL) { return NULL; } memset(sc, 0, sizeof(struct mpegts_stream_ctx)); sc->index = s->nb_streams; s->streams[s->nb_streams++] = sc; return sc; } static int mpegts_set_stream_info(struct mpegts_stream_ctx *st, mpegts_pes_context *pes, uint32_t stream_type, uint32_t prog_reg_desc) { int old_codec_type = st->codecpar.codec_type; int old_codec_id = st->codecpar.codec_id; struct mpegts_context *ts = pes->ts; // avpriv_set_pts_info(st, 33, 1, 90000); st->priv_data = pes; st->codecpar.codec_type = MPP_MEDIA_TYPE_OTHER; st->codecpar.codec_id = CODEC_ID_NONE; pes->st = st; pes->stream_type = stream_type; logd("stream=%d stream_type=%x pid=%x prog_reg_desc=%.4s\n", st->index, pes->stream_type, pes->pid, (char *)&prog_reg_desc); st->codecpar.codec_tag = pes->stream_type; mpegts_find_stream_type(st, pes->stream_type, iso_types); if (st->codecpar.codec_id == CODEC_ID_NONE) { st->codecpar.codec_id = old_codec_id; st->codecpar.codec_type = old_codec_type; } if (st->codecpar.codec_type == MPP_MEDIA_TYPE_AUDIO) { ts->has_audio = 1; } return 0; } static int mpegts_set_audio_info(struct mpegts_stream_ctx *st, mpegts_pes_context *pes) { int ret = PARSER_OK; struct mpegts_context *ts = pes->ts; struct mpegts_audio_decode_header audio_header = {0}; if (ts->cur_codec_id == CODEC_ID_MP3) { ret = mpegaudio_decode_mp3_header(ts->pkt.data + ts->read_offset, &audio_header); if (ret < 0) { loge("mpegaudio_decode_mp3_header failed, ret:%d", ret); return ret; } } else if (ts->cur_codec_id == CODEC_ID_AAC) { ret = mpegaudio_decode_aac_header(ts->pkt.data + ts->read_offset, &audio_header); if (ret < 0) { loge("mpegaudio_decode_aac_header failed, ret:%d", ret); return ret; } } st->codecpar.bits_per_coded_sample = 16; st->codecpar.channels = audio_header.nb_channels; st->codecpar.sample_rate = audio_header.sample_rate; logi("get audio params: bits_per_coded_sample=%d channels=%d sample_rate=%d\n", st->codecpar.bits_per_coded_sample, st->codecpar.channels, st->codecpar.sample_rate); return 0; } static void reset_pes_packet_state(mpegts_pes_context *pes) { pes->pts = 0; pes->dts = 0; pes->data_index = 0; pes->flags = 0; } static int new_pes_packet(mpegts_pes_context *pes, struct aic_parser_packet *pkt) { pkt->type = mpegts_get_pkt_codec_type(pes->stream_type, iso_types); pkt->size = pes->data_index; pkt->pts = pes->pts; pkt->dts = 0; pkt->flag = pes->flags; pkt->duration = 0; reset_pes_packet_state(pes); return 0; } int mpegts_skip_h264_nalu_aud(struct mpegts_stream_ctx *st, const uint8_t *buf) { if (st->codecpar.codec_type != MPP_MEDIA_TYPE_VIDEO || st->codecpar.codec_id != CODEC_ID_H264) { return 0; } int i = 0, j = 0; int offset = 0; int find_aud_off = 0; const uint8_t *tmp_buf = buf; for (i = 0; i < 16; i++) { if (tmp_buf[i] == 0 && tmp_buf[i + 1] == 0 && tmp_buf[i + 2] == 1 && tmp_buf[i + 3] == 9) { find_aud_off = i + 3; break; } } if (find_aud_off) { for (j = find_aud_off; j < find_aud_off + 16; j++) { if (tmp_buf[j] == 0 && tmp_buf[j + 1] == 0 && tmp_buf[j + 2] == 1) { if (tmp_buf[j - 1] == 0) { offset = j - 1; } else { offset = j; } break; } } if (offset == 0) offset = PES_H264_NAL_AUD_SIZE; } return offset; } static int mpegts_start_pes(mpegts_pes_context *pes) { int ret = -1; struct mpegts_context *ts = pes->ts; mpegts_pes_context *last_pes = ts->last_pes; if (last_pes) { if (last_pes->state == MPEGTS_PAYLOAD && last_pes->data_index > 0) { memcpy(ts->pkt.data, ts->first_pkt, ts->first_pkt_size); ts->cur_codec_id = mpegts_get_pkt_codec_id(last_pes->stream_type, iso_types); ret = new_pes_packet(last_pes, &ts->pkt); if (ret < 0) return ret; ts->stop_parse = 1; /*find the first audio then clear find flag*/ if (ts->find_first_audio && ts->pkt.type == MPP_MEDIA_TYPE_AUDIO) { mpegts_set_audio_info(last_pes->st, last_pes); ts->find_first_audio = 0; } } else { loge("last pes is null should be not happend!!!"); } } reset_pes_packet_state(pes); ts->read_offset = 0; ts->no_need_peek = 0; ts->last_pes = NULL; pes->state = MPEGTS_HEADER; return 0; } static int mpegts_pes_header(mpegts_pes_context *pes) { int code = 0; struct mpegts_context *ts = pes->ts; if (pes->data_index == PES_START_SIZE) { /* we got all the PES or section header. We can now * decide */ if (pes->header[0] == 0x00 && pes->header[1] == 0x00 && pes->header[2] == 0x01) { /* it must be an MPEG-2 PES stream */ code = pes->header[3] | 0x100; logd("pid=%x pes_code=%#x\n", pes->pid, code); pes->stream_id = pes->header[3]; /* stream not present in PMT */ if (!pes->st) { if (ts->skip_changes) goto skip; if (ts->merge_pmt_versions) goto skip; /* wait for PMT to merge new stream */ pes->st = mpegts_new_stream(ts->parser); if (!pes->st) return PARSER_NOMEM; pes->st->index = pes->pid; mpegts_set_stream_info(pes->st, pes, 0, 0); } pes->buffer = ts->pkt.data; memset(ts->first_pkt, 0, TS_PACKET_SIZE); ts->first_pkt_size = 0; ts->last_pes = pes; pes->total_size = MAX_PES_PAYLOAD; if (code != 0x1bc && code != 0x1bf && /* program_stream_map, private_stream_2 */ code != 0x1f0 && code != 0x1f1 && /* ECM, EMM */ code != 0x1ff && code != 0x1f2 && /* program_stream_directory, DSMCC_stream */ code != 0x1f8) { /* ITU-T Rec. H.222.1 type E stream */ pes->state = MPEGTS_PESHEADER; } else { pes->pes_header_size = 6; pes->state = MPEGTS_PAYLOAD; pes->data_index = 0; } } else { /* otherwise, it should be a table */ /* skip packet */ skip: pes->state = MPEGTS_SKIP; return 1; } } return 0; } static void mpegts_pes_header_fill(mpegts_pes_context *pes) { if (pes->data_index == pes->pes_header_size) { const uint8_t *r; unsigned int flags, pes_ext, skip; flags = pes->header[7]; r = pes->header + 9; pes->pts = 0; pes->dts = 0; if ((flags & 0xc0) == 0x80) { pes->dts = pes->pts = mpegts_parse_pes_pts(r) * 1000000 / TS_TIMESTAMP_BASE_HZ; r += 5; } else if ((flags & 0xc0) == 0xc0) { pes->pts = mpegts_parse_pes_pts(r) * 1000000 / TS_TIMESTAMP_BASE_HZ; r += 5; pes->dts = mpegts_parse_pes_pts(r) * 1000000 / TS_TIMESTAMP_BASE_HZ; r += 5; } pes->extended_stream_id = -1; if (flags & 0x01) { /* PES extension */ pes_ext = *r++; /* Skip PES private data, program packet sequence counter and P-STD buffer */ skip = (pes_ext >> 4) & 0xb; skip += skip & 0x9; r += skip; if ((pes_ext & 0x41) == 0x01 && (r + 2) <= (pes->header + pes->pes_header_size)) { /* PES extension 2 */ if ((r[0] & 0x7f) > 0 && (r[1] & 0x80) == 0) pes->extended_stream_id = r[1]; } } /* we got the full header. We parse it and get the payload */ pes->state = MPEGTS_PAYLOAD; pes->data_index = 0; } } /* return non zero if a packet could be constructed */ static int mpegts_push_data(mpegts_ts_filter *filter, const uint8_t *buf, int buf_size, int is_start, int64_t pos) { mpegts_pes_context *pes = filter->u.pes_filter.opaque; struct mpegts_context *ts = pes->ts; const uint8_t *p; int ret = -1, len; if (is_start) { ret = mpegts_start_pes(pes); if (ret < 0) return ret; pes->ts_packet_pos = pos; } p = buf; while (buf_size > 0) { switch (pes->state) { case MPEGTS_HEADER: len = PES_START_SIZE - pes->data_index; if (len > buf_size) len = buf_size; memcpy(pes->header + pes->data_index, p, len); pes->data_index += len; p += len; buf_size -= len; if (mpegts_pes_header(pes)) { continue; } break; /**********************************************/ /* PES packing parsing */ case MPEGTS_PESHEADER: len = PES_HEADER_SIZE - pes->data_index; if (len < 0) return PARSER_INVALIDDATA; if (len > buf_size) len = buf_size; memcpy(pes->header + pes->data_index, p, len); pes->data_index += len; p += len; buf_size -= len; if (pes->data_index == PES_HEADER_SIZE) { pes->pes_header_size = pes->header[8] + 9; pes->state = MPEGTS_PESHEADER_FILL; } break; case MPEGTS_PESHEADER_FILL: len = pes->pes_header_size - pes->data_index; if (len < 0) return PARSER_INVALIDDATA; if (len > buf_size) len = buf_size; memcpy(pes->header + pes->data_index, p, len); pes->data_index += len; p += len; buf_size -= len; mpegts_pes_header_fill(pes); break; case MPEGTS_PAYLOAD: if (pes->buffer) { if (pes->data_index > 0 && pes->data_index + buf_size > pes->total_size) { loge("frame size %d overange total size %d, then drop it", pes->data_index + buf_size, pes->total_size); ts->stop_parse = 1; } else if (pes->data_index == 0 && buf_size > pes->total_size) { // pes packet size is < ts size packet and pes data is padded with 0xff // not sure if this is legal in ts but see issue #2392 buf_size = pes->total_size; } if (is_start) { if (buf_size < TS_PACKET_SIZE) { int offset = mpegts_skip_h264_nalu_aud(pes->st, p); logd("skip offset %d, buf_size %d", offset, buf_size); buf_size -= offset; memcpy(ts->first_pkt, p + offset, buf_size); ts->first_pkt_size = buf_size; } else { loge("first payload(%d) shoule be small than(%d)", buf_size, TS_PACKET_SIZE); return -1; } } else { memcpy(pes->buffer + pes->data_index, p, buf_size); } pes->data_index += buf_size; /* emit complete packets with known packet size * decreases demuxer delay for infrequent packets like subtitles from * a couple of seconds to milliseconds for properly muxed files. * total_size is the number of bytes following pes_packet_length * in the pes header, i.e. not counting the first PES_START_SIZE bytes */ if (!ts->stop_parse && pes->total_size < MAX_PES_PAYLOAD && pes->pes_header_size + pes->data_index == pes->total_size + PES_START_SIZE) { ts->stop_parse = 1; } } buf_size = 0; break; case MPEGTS_SKIP: buf_size = 0; break; } } return 0; } static mpegts_pes_context *add_pes_stream(struct mpegts_context *ts, int pid, int pcr_pid) { mpegts_ts_filter *tss; mpegts_pes_context *pes; /* if no pid found, then add a pid context */ pes = mpp_alloc(sizeof(mpegts_pes_context)); if (!pes) return 0; memset(pes, 0, sizeof(mpegts_pes_context)); pes->ts = ts; pes->parser = ts->parser; pes->pid = pid; pes->state = MPEGTS_SKIP; pes->pts = 0; pes->dts = 0; tss = mpegts_open_pes_filter(ts, pid, mpegts_push_data, pes); if (!tss) { mpp_free(pes); return NULL; } return pes; } static struct mpegts_stream_ctx *find_matching_stream(mpegts_context *ts, int pid, unsigned int programid, int stream_identifier, int pmt_stream_idx) { struct aic_mpegts_parser *s = ts->parser; int i; struct mpegts_stream_ctx *found = NULL; for (i = 0; i < s->nb_streams; i++) { struct mpegts_stream_ctx *st = s->streams[i]; if (st->program_num != programid) continue; /* match based on "stream identifier descriptor" if present */ if (stream_identifier != -1) { if (st->stream_identifier == stream_identifier + 1) { found = st; break; } } else if (st->pmt_stream_idx == pmt_stream_idx) { found = st; /* match based on position within the PMT */ break; } } return found; } static int is_pes_stream(int stream_type, uint32_t prog_reg_desc) { return !(stream_type == 0x13 || (stream_type == 0x86 && prog_reg_desc == AIC_RL32("CUEI"))); } static void sdt_cb(mpegts_ts_filter *filter, const uint8_t *section, int section_len) { return; } static mpegts_pes_context* create_pmt_stream(mpegts_context *ts, mpegts_section_header *h, int stream_type, int stream_idx, int pid, int pcr_pid) { struct mpegts_stream_ctx *st = NULL; mpegts_pes_context *pes = NULL; uint32_t prog_reg_desc = 0; /* registration descriptor */ int stream_identifier = -1; if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { pes = ts->pids[pid]->u.pes_filter.opaque; if (ts->merge_pmt_versions && !pes->st) { st = find_matching_stream(ts, pid, h->id, stream_identifier, stream_idx); if (st) { pes->st = st; pes->stream_type = stream_type; pes->merged_st = 1; } } if (!pes->st) { pes->st = mpegts_new_stream(pes->parser); if (!pes->st) return NULL; pes->st->index = pes->pid; pes->st->program_num = h->id; pes->st->pmt_stream_idx = stream_idx; } st = pes->st; } else if (is_pes_stream(stream_type, prog_reg_desc)) { if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid); if (ts->merge_pmt_versions && pes && !pes->st) { st = find_matching_stream(ts, pid, h->id, stream_identifier, stream_idx); if (st) { pes->st = st; pes->stream_type = stream_type; pes->merged_st = 1; } } if (pes && !pes->st) { st = mpegts_new_stream(pes->parser); if (!st) return NULL; st->index = pes->pid; st->program_num = h->id; st->pmt_stream_idx = stream_idx; } } if (!st) return NULL; if (pes && !pes->stream_type) { mpegts_set_stream_info(st, pes, stream_type, prog_reg_desc); } return pes; } static void pmt_cb(mpegts_ts_filter *filter, const uint8_t *section, int section_len) { mpegts_context *ts = filter->u.section_filter.opaque; mpegts_section_header h1, *h = &h1; const uint8_t *p, *p_end, *desc_list_end; int program_info_length, pcr_pid, pid, stream_type; int desc_list_len; int i; p_end = section + section_len - 4; p = section; if (parse_section_header(h, &p, p_end) < 0) return; if (h->tid != PMT_TID) /* table_id = 0x2*/ return; // stop parsing after pmt, we found header if (ts->skip_pmt) return; pcr_pid = get16(&p, p_end); /*drop pcr id*/ logi("PMT: len %i\n", section_len); logi("sid=0x%x sec_num=%d/%d version=%d tid=%d\n", h->id, h->sec_num, h->last_sec_num, h->version, h->tid); logi("pcr_pid=0x%x\n", pcr_pid); program_info_length = get16(&p, p_end); program_info_length &= 0xfff; p += program_info_length; if (p >= p_end) return; ts->skip_pmt = 1; for (i = 0;; i++) { stream_type = get8(&p, p_end); /* get video and audio type*/ if (stream_type < 0) break; pid = get16(&p, p_end); if (pid < 0) return; pid &= 0x1fff; if (pid == ts->current_pid) return; if (create_pmt_stream(ts, h, stream_type, i, pid, pcr_pid) == NULL) { return; } desc_list_len = get16(&p, p_end); if (desc_list_len < 0) return; desc_list_len &= 0xfff; desc_list_end = p + desc_list_len; if (desc_list_end > p_end) return; } } static void pat_cb(mpegts_ts_filter *filter, const uint8_t *section, int section_len) { struct mpegts_context *ts = filter->u.section_filter.opaque; mpegts_section_header h1, *h = &h1; const uint8_t *p, *p_end; int sid, pmt_pid; p_end = section + section_len - 4; p = section; if (parse_section_header(h, &p, p_end) < 0) return; if (h->tid != PAT_TID) return; if (ts->skip_changes) return; ts->skip_changes = 1; logi("PAT:\n"); for (;;) { sid = get16(&p, p_end); if (sid < 0) break; pmt_pid = get16(&p, p_end); if (pmt_pid < 0) break; pmt_pid &= 0x1fff; if (pmt_pid == ts->current_pid) break; logd("sid=0x%x pid=0x%x\n", sid, pmt_pid); if (sid == 0x0000) { /* NIT info */ } else { mpegts_ts_filter *fil = ts->pids[pmt_pid]; if (fil) if (fil->type != MPEGTS_SECTION || fil->pid != pmt_pid || fil->u.section_filter.section_cb != pmt_cb) mpegts_close_filter(ts, ts->pids[pmt_pid]); /* Program Map Table: parse stream type */ if (!ts->pids[pmt_pid]) mpegts_open_section_filter(ts, pmt_pid, pmt_cb, ts, 1); break; } } } /* return the 90kHz PCR and the extension for the 27MHz PCR. return * (-1) if not available */ static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, const uint8_t *packet) { int afc, len, flags; const uint8_t *p; unsigned int v; afc = (packet[3] >> 4) & 3; if (afc <= 1) return PARSER_INVALIDDATA; p = packet + 4; len = p[0]; p++; if (len == 0) return PARSER_INVALIDDATA; flags = *p++; len--; if (!(flags & 0x10)) return PARSER_INVALIDDATA; if (len < 6) return PARSER_INVALIDDATA; v = AIC_RB32(p); *ppcr_high = ((int64_t)v << 1) | (p[4] >> 7); *ppcr_low = ((p[4] & 1) << 8) | p[5]; return 0; } /* handle one TS packet */ static int handle_packet(struct mpegts_context *ts, const uint8_t *packet, int64_t pos) { mpegts_ts_filter *tss; int len, pid, cc, expected_cc, cc_ok, afc, is_start, is_discontinuity, has_adaptation, has_payload; const uint8_t *p, *p_end; pid = AIC_RB16(packet + 1) & 0x1fff; is_start = packet[1] & 0x40; /* payload unit start indicator */ tss = ts->pids[pid]; if (ts->auto_guess && !tss && is_start) { add_pes_stream(ts, pid, -1); tss = ts->pids[pid]; } if (!tss) return 0; ts->current_pid = pid; afc = (packet[3] >> 4) & 3; if (afc == 0) /* reserved value */ return 0; has_adaptation = afc & 2; has_payload = afc & 1; is_discontinuity = has_adaptation && packet[4] != 0 && /* with length > 0 */ (packet[5] & 0x80); /* and discontinuity indicated */ /* continuity check (currently not used) */ cc = (packet[3] & 0xf); expected_cc = has_payload ? (tss->last_cc + 1) & 0x0f : tss->last_cc; cc_ok = pid == 0x1FFF || // null packet PID is_discontinuity || tss->last_cc < 0 || expected_cc == cc; tss->last_cc = cc; if (!cc_ok) { logd("Continuity check failed for pid %d expected %d got %d\n", pid, expected_cc, cc); if (tss->type == MPEGTS_PES) { mpegts_pes_context *pc = tss->u.pes_filter.opaque; pc->flags |= 0x2; } } p = packet + 4; if (has_adaptation) { int64_t pcr_h; int pcr_l; if (parse_pcr(&pcr_h, &pcr_l, packet) == 0) tss->last_pcr = pcr_h * 300 + pcr_l; /* skip adaptation field */ p += p[0] + 1; } /* if past the end of packet, ignore */ p_end = packet + TS_PACKET_SIZE; if (p >= p_end || !has_payload) return 0; if (pos >= 0) { mpp_assert(pos >= TS_PACKET_SIZE); ts->pos47_full = pos - TS_PACKET_SIZE; } if (tss->type == MPEGTS_SECTION) { if (is_start) { /* pointer field present */ len = *p++; if (len > p_end - p) return 0; if (len && cc_ok) { /* write remaining section bytes */ write_section_data(ts, tss, p, len, 0); /* check whether filter has been closed */ if (!ts->pids[pid]) return 0; } p += len; if (p < p_end) { write_section_data(ts, tss, p, p_end - p, 1); } } else { if (cc_ok) { write_section_data(ts, tss, p, p_end - p, 0); } } } else { int ret; // Note: The position here points actually behind the current packet. if (tss->type == MPEGTS_PES) { if ((ret = tss->u.pes_filter.pes_cb(tss, p, p_end - p, is_start, pos - ts->raw_packet_size)) < 0) return ret; } } return 0; } static int mpegts_resync(struct aic_mpegts_parser *s, int seekback, const uint8_t *current_packet) { struct mpegts_context *ts = s->priv_data; struct aic_stream *pb = s->stream; int c, i; uint64_t pos = aic_stream_tell(pb); int64_t back = MPP_MIN(seekback, pos); // Special case for files like 01c56b0dc1.ts if (current_packet[0] == 0x80 && current_packet[12] == 0x47) { aic_stream_seek(pb, 12 - back, SEEK_CUR); return 0; } aic_stream_seek(pb, -back, SEEK_CUR); for (i = 0; i < ts->resync_size; i++) { c = aic_stream_r8(pb); if (c == 0x47) { // TS Packet Header int new_packet_size; aic_stream_seek(pb, -1, SEEK_CUR); pos = aic_stream_tell(pb); new_packet_size = get_packet_size(s); if (new_packet_size > 0 && new_packet_size != ts->raw_packet_size) { logw("changing packet size to %d\n", new_packet_size); ts->raw_packet_size = new_packet_size; } aic_stream_seek(pb, pos, SEEK_SET); return 0; } } loge("max resync size reached, could not find sync byte\n"); /* no sync found */ return PARSER_INVALIDDATA; } static int read_packet(struct aic_mpegts_parser *s, uint8_t *buf, int raw_packet_size) { struct aic_stream *pb = s->stream; int len; for (;;) { len = aic_stream_read(pb, buf, TS_PACKET_SIZE); if (len != TS_PACKET_SIZE) return len < 0 ? len : PARSER_EOS; /* check packet sync byte */ if (buf[0] != 0x47) { /* find a new packet start */ if (mpegts_resync(s, raw_packet_size, buf) < 0) return PARSER_ERROR; else continue; } else { break; } } return 0; } static void finished_reading_packet(struct aic_mpegts_parser *s, int raw_packet_size) { struct aic_stream *pb = s->stream; int skip = raw_packet_size - TS_PACKET_SIZE; if (skip > 0) aic_stream_skip(pb, skip); } static int handle_packets(struct mpegts_context *ts, int64_t nb_packets) { struct aic_mpegts_parser *s = ts->parser; struct aic_stream *pb = s->stream; uint8_t packet[TS_PACKET_SIZE + MPEGTS_INPUT_BUFFER_PADDING_SIZE]; const uint8_t *data; int64_t packet_num; int ret = 0; if (aic_stream_tell(pb) != ts->last_pos) { int i; logi("Skipping after seek\n"); /* seek detected, flush pes buffer */ for (i = 0; i < NB_PID_MAX; i++) { if (ts->pids[i]) { if (ts->pids[i]->type == MPEGTS_PES) { mpegts_pes_context *pes = ts->pids[i]->u.pes_filter.opaque; pes->data_index = 0; pes->state = MPEGTS_SKIP; /* skip until pes header */ } else if (ts->pids[i]->type == MPEGTS_SECTION) { ts->pids[i]->u.section_filter.last_ver = -1; } ts->pids[i]->last_cc = -1; ts->pids[i]->last_pcr = -1; } } } ts->stop_parse = 0; packet_num = 0; memset(packet + TS_PACKET_SIZE, 0, MPEGTS_INPUT_BUFFER_PADDING_SIZE); for (;;) { packet_num++; if ((nb_packets != 0 && packet_num > nb_packets) || ts->stop_parse > 1) { ret = PARSER_NODATA; break; } if (!ts->find_first_audio) { if (ts->stop_parse > 0) break; } ret = read_packet(s, packet, ts->raw_packet_size); if (ret != 0) break; data = packet; ret = handle_packet(ts, data, aic_stream_tell(pb)); finished_reading_packet(s, ts->raw_packet_size); if (ret != 0) break; } ts->last_pos = aic_stream_tell(pb); return ret; } int mpegts_read_header(struct aic_mpegts_parser *s) { struct mpegts_context *ts = NULL; s->priv_data = mpp_alloc(sizeof(struct mpegts_context)); if (!s->priv_data) { return PARSER_NOMEM; } memset(s->priv_data, 0, sizeof(struct mpegts_context)); ts = s->priv_data; ts->parser = s; ts->auto_guess = 1; ts->raw_packet_size = TS_PACKET_SIZE; ts->find_first_audio = 0; ts->pkt.size = 0; ts->pkt.data = mpp_alloc(MAX_PES_PAYLOAD); if (!ts->pkt.data) { loge("malloc temp buffer size %d failed", MAX_PES_PAYLOAD); mpp_free(s->priv_data); s->priv_data = NULL; return PARSER_NOMEM; } /* Service Description Table: useless data, discard */ mpegts_open_section_filter(ts, SDT_PID, sdt_cb, ts, 1); /* Program Association Table */ mpegts_open_section_filter(ts, PAT_PID, pat_cb, ts, 1); /* Read SDT、PAT and PMT get video and audio */ handle_packets(ts, 3); if (ts->has_audio) { /* Save current pos, and then search the first audio pkt to get audio params*/ uint64_t pos = aic_stream_tell(s->stream); ts->find_first_audio = 1; handle_packets(ts, 0); ts->find_first_audio = 0; ts->last_pes = NULL; aic_stream_seek(s->stream, pos, SEEK_SET); } return PARSER_OK; } static int handle_audio_packets(struct mpegts_context *ts, struct aic_parser_packet *pkt) { int ret = PARSER_OK; int new_read_offset = 0; struct mpegts_audio_decode_header audio_header = {0}; if (ts->cur_codec_id == CODEC_ID_MP3) { ret = mpegaudio_decode_mp3_header(ts->pkt.data + ts->read_offset, &audio_header); if (ret < 0) return ret; new_read_offset = ts->read_offset + audio_header.frame_size; if (new_read_offset <= ts->pkt.size) { ts->no_need_peek = (new_read_offset == ts->pkt.size) ? 0 : 1; pkt->size = audio_header.frame_size; pkt->pts += audio_header.frame_duration; } else { if (ts->read_offset < ts->pkt.size) loge("Audio packet may wrong, read_offset:%"PRIu32", pkt.size:%d, new frame_size:%d", ts->read_offset, ts->pkt.size, audio_header.frame_size); ts->no_need_peek = 0; } } else if (ts->cur_codec_id == CODEC_ID_AAC) { ret = mpegaudio_decode_aac_header(ts->pkt.data + ts->read_offset, &audio_header); if (ret < 0) return ret; new_read_offset = ts->read_offset + audio_header.frame_size; if (new_read_offset <= ts->pkt.size) { ts->no_need_peek = (new_read_offset == ts->pkt.size) ? 0 : 1; ts->read_offset += audio_header.aac.header_offset; pkt->size = audio_header.frame_size - audio_header.aac.header_offset; pkt->pts += audio_header.frame_duration; } else { ts->no_need_peek = 0; } } else { ts->no_need_peek = 0; } return ret; } static int update_audio_packets(struct mpegts_context *ts, struct aic_parser_packet *pkt) { if (ts->cur_codec_id != CODEC_ID_MP3 && ts->cur_codec_id != CODEC_ID_AAC) { return PARSER_OK; } if (ts->no_need_peek) { ts->read_offset += pkt->size; } return PARSER_OK; } int mpegts_peek_packet(struct aic_mpegts_parser *s, struct aic_parser_packet *pkt) { if (!s->priv_data) { return PARSER_NOMEM; } int ret = PARSER_OK; struct mpegts_context *ts = s->priv_data; /* Read and combained all es packet of one frame to temp buffer*/ if (ts->no_need_peek == 0) { ret = handle_packets(ts, 0); if (ret == PARSER_EOS) { pkt->size = 0; pkt->flag = PACKET_EOS; } else { pkt->type = ts->pkt.type; pkt->pts = ts->pkt.pts; pkt->dts = ts->pkt.dts; pkt->flag = ts->pkt.flag; pkt->duration = ts->pkt.duration; ts->read_offset = 0; pkt->size = ts->pkt.size; if (ts->pkt.type == MPP_MEDIA_TYPE_AUDIO) { handle_audio_packets(ts, pkt); } else { ts->no_need_peek = 0; } } } else { ret = handle_audio_packets(ts, pkt); } logd("peek %d no_need_peek %"PRIu32", packet: type=%d, size=%d, pts=%lld", ret, ts->no_need_peek, pkt->type, pkt->size, pkt->pts); return ret; } int mpegts_read_packet(struct aic_mpegts_parser *s, struct aic_parser_packet *pkt) { if (!pkt || !s->priv_data) { return PARSER_NOMEM; } struct mpegts_context *ts = s->priv_data; memcpy(pkt->data, ts->pkt.data + ts->read_offset, pkt->size); if (ts->pkt.type == MPP_MEDIA_TYPE_AUDIO) { update_audio_packets(ts, pkt); } return PARSER_OK; } int mpegts_seek_packet(struct aic_mpegts_parser *s, s64 pts) { return PARSER_ERROR; } static void mpegts_free(struct mpegts_context *ts) { int i; for (i = 0; i < NB_PID_MAX; i++) if (ts->pids[i]) mpegts_close_filter(ts, ts->pids[i]); } int mpegts_read_close(struct aic_mpegts_parser *s) { int i = 0; struct mpegts_context *ts = s->priv_data; for (i = 0; i < s->nb_streams; i++) { struct mpegts_stream_ctx *st = s->streams[i]; if (!st) { continue; } mpp_free(st); s->streams[i] = NULL; } if (!ts) { return PARSER_NOMEM; } if (ts->pkt.data) { mpp_free(ts->pkt.data); ts->pkt.data = NULL; } mpegts_free(ts); mpp_free(ts); return PARSER_OK; }