| /* |
| * drivers/amlogic/dvb/demux/sc2_demux/ts_output.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/vmalloc.h> |
| #include <linux/of.h> |
| #include <linux/spinlock.h> |
| #include <linux/kthread.h> |
| #include <linux/wait.h> |
| #include <linux/slab.h> |
| #include <linux/delay.h> |
| #include <linux/string.h> |
| #include <linux/dvb/dmx.h> |
| #include <linux/version.h> |
| #include <linux/module.h> |
| #include <linux/dma-mapping.h> |
| |
| #include "sc2_control.h" |
| #include "ts_output.h" |
| #include "mem_desc.h" |
| #include "../../aucpu/aml_aucpu.h" |
| #include "../aml_dvb.h" |
| #include "../dmx_log.h" |
| #include <linux/fs.h> |
| |
| #define MAX_TS_PID_NUM 1024 |
| #define MAX_SID_NUM 64 |
| #define MAX_REMAP_NUM 32 |
| #define MAX_ES_NUM 64 |
| #define MAX_OUT_ELEM_NUM 128 |
| #define MAX_PCR_NUM 16 |
| |
| #define MAX_READ_BUF_LEN (64 * 1024) |
| #define MAX_DVR_READ_BUF_LEN (2 * 1024 * 1024) |
| |
| #define MAX_FEED_NUM 32 |
| static int ts_output_max_pid_num_per_sid = 16; |
| /*protect cb_list/ts output*/ |
| static struct mutex *ts_output_mutex; |
| static struct mutex es_output_mutex; |
| |
| struct es_params_t { |
| struct dmx_non_sec_es_header header; |
| char last_last_header[16]; |
| char last_header[16]; |
| u8 have_header; |
| u8 have_send_header; |
| unsigned long data_start; |
| unsigned int data_len; |
| int es_overflow; |
| int es_error_cn; |
| u32 header_wp; |
| }; |
| |
| struct ts_out { |
| struct out_elem *pout; |
| struct es_params_t *es_params; |
| struct ts_out *pnext; |
| }; |
| |
| struct ts_out_task { |
| int running; |
| wait_queue_head_t wait_queue; |
| struct task_struct *out_task; |
| u16 flush_time_ms; |
| struct timer_list out_timer; |
| struct ts_out *ts_out_list; |
| }; |
| |
| struct pid_entry { |
| u8 used; |
| u16 id; |
| u16 pid; |
| u16 pid_mask; |
| u8 dmx_id; |
| u8 ref; |
| struct out_elem *pout; |
| struct pid_entry *pnext; |
| }; |
| |
| struct cb_entry { |
| u8 id; |
| u8 format; |
| u8 ref; |
| u8 demux_id; |
| ts_output_cb cb; |
| void *udata[MAX_FEED_NUM]; |
| struct cb_entry *next; |
| }; |
| |
| struct dump_file { |
| loff_t file_pos; |
| struct file *file_fp; |
| }; |
| |
| struct out_elem { |
| u8 used; |
| u8 sid; |
| u8 enable; |
| u8 ref; |
| u8 dmx_id; |
| enum output_format format; |
| enum content_type type; |
| int media_type; |
| |
| struct pid_entry *pid_list; |
| struct es_entry *es_pes; |
| struct chan_id *pchan; |
| struct chan_id *pchan1; |
| struct pid_entry *pcrpid_list; |
| |
| char *cache; |
| u16 cache_len; |
| u16 remain_len; |
| struct cb_entry *cb_sec_list; |
| struct cb_entry *cb_ts_list; |
| u16 flush_time_ms; |
| int running; |
| u8 output_mode; |
| |
| s32 aucpu_handle; |
| u8 aucpu_start; |
| unsigned long aucpu_mem_phy; |
| unsigned long aucpu_mem; |
| unsigned int aucpu_mem_size; |
| unsigned int aucpu_read_offset; |
| __u64 newest_pts; |
| |
| /*pts/dts for aucpu*/ |
| s32 aucpu_pts_handle; |
| u8 aucpu_pts_start; |
| unsigned long aucpu_pts_mem_phy; |
| unsigned long aucpu_pts_mem; |
| unsigned int aucpu_pts_mem_size; |
| unsigned int aucpu_pts_r_offset; |
| |
| struct dump_file dump_file; |
| }; |
| |
| struct sid_entry { |
| int used; |
| int pid_entry_begin; |
| int pid_entry_num; |
| }; |
| |
| struct remap_entry { |
| int status; |
| u8 stream_id; |
| int remap_flag; |
| int pid_entry; |
| int pid; |
| int pid_new; |
| }; |
| |
| struct es_entry { |
| u8 used; |
| u8 buff_id; |
| u8 id; |
| u8 dmx_id; |
| int status; //-1:off; |
| int pid; |
| struct out_elem *pout; |
| }; |
| |
| struct pcr_entry { |
| u8 turn_on; |
| u8 stream_id; |
| int pcr_pid; |
| }; |
| |
| static struct pid_entry *pid_table; |
| static struct sid_entry sid_table[MAX_SID_NUM]; |
| static struct remap_entry remap_table[MAX_REMAP_NUM]; |
| static struct es_entry es_table[MAX_ES_NUM]; |
| static struct out_elem *out_elem_table; |
| static struct pcr_entry pcr_table[MAX_PCR_NUM]; |
| static struct ts_out_task ts_out_task_tmp; |
| static struct ts_out_task es_out_task_tmp; |
| static int timer_wake_up; |
| static int timer_es_wake_up; |
| |
| #define dprint(fmt, args...) \ |
| dprintk(LOG_ERROR, debug_ts_output, "ts_output:" fmt, ## args) |
| #define dprintk_info(fmt, args...) \ |
| dprintk(LOG_ERROR, debug_ts_output, fmt, ## args) |
| #define pr_dbg(fmt, args...) \ |
| dprintk(LOG_DBG, debug_ts_output, "ts_output:" fmt, ## args) |
| |
| MODULE_PARM_DESC(debug_ts_output, "\n\t\t Enable demux debug information"); |
| static int debug_ts_output; |
| module_param(debug_ts_output, int, 0644); |
| |
| MODULE_PARM_DESC(drop_dup, "\n\t\t drop duplicate packet"); |
| static int drop_dup; |
| module_param(drop_dup, int, 0644); |
| |
| MODULE_PARM_DESC(dump_video_es, "\n\t\t dump video es packet"); |
| static int dump_video_es; |
| module_param(dump_video_es, int, 0644); |
| |
| MODULE_PARM_DESC(dump_audio_es, "\n\t\t dump audio es packet"); |
| static int dump_audio_es; |
| module_param(dump_audio_es, int, 0644); |
| |
| MODULE_PARM_DESC(dump_dvr_ts, "\n\t\t dump dvr ts packet"); |
| static int dump_dvr_ts; |
| module_param(dump_dvr_ts, int, 0644); |
| |
| struct dump_file dvr_dump_file; |
| |
| #define VIDEOES_DUMP_FILE "/data/video_dump" |
| #define AUDIOES_DUMP_FILE "/data/audio_dump" |
| #define DVR_DUMP_FILE "/data/dvr_dump" |
| |
| #define READ_CACHE_SIZE (188) |
| |
| static int out_flush_time = 10; |
| static int out_es_flush_time = 10; |
| |
| static int _handle_es(struct out_elem *pout, struct es_params_t *es_params); |
| static int start_aucpu_non_es(struct out_elem *pout); |
| static int aucpu_bufferid_read(struct out_elem *pout, |
| char **pread, unsigned int len, int is_pts); |
| |
| static void dump_file_open(char *path, struct dump_file *dump_file_fp, |
| int sid, int pid, int is_ts) |
| { |
| int i = 0; |
| char whole_path[255]; |
| struct file *file_fp; |
| |
| if (dump_file_fp->file_fp) |
| return; |
| |
| //find new file name |
| while (i < 999) { |
| if (is_ts) |
| snprintf((char *)&whole_path, sizeof(whole_path), |
| "%s_%03d.ts", path, i); |
| else |
| snprintf((char *)&whole_path, sizeof(whole_path), |
| "%s_0x%0x_0x%0x_%03d.es", path, sid, pid, i); |
| |
| file_fp = filp_open(whole_path, O_RDONLY, 0666); |
| if (IS_ERR(file_fp)) |
| break; |
| filp_close(file_fp, current->files); |
| i++; |
| } |
| dump_file_fp->file_fp = filp_open(whole_path, |
| O_CREAT | O_RDWR | O_APPEND, 0666); |
| if (IS_ERR(dump_file_fp->file_fp)) { |
| pr_err("create video dump [%s] file failed [%d]\n", |
| whole_path, (int)PTR_ERR(dump_file_fp->file_fp)); |
| dump_file_fp->file_fp = NULL; |
| } else { |
| dprint("create dump [%s] success\n", whole_path); |
| } |
| } |
| |
| static void dump_file_write( |
| char *buf, size_t count, struct dump_file *dump_file_fp) |
| { |
| mm_segment_t old_fs; |
| |
| if (!dump_file_fp->file_fp) { |
| pr_err("Failed to write video dump file fp is null\n"); |
| return; |
| } |
| if (count == 0) |
| return; |
| |
| old_fs = get_fs(); |
| set_fs(KERNEL_DS); |
| |
| if (count != vfs_write(dump_file_fp->file_fp, buf, count, |
| &dump_file_fp->file_pos)) |
| pr_err("Failed to write dump file\n"); |
| |
| set_fs(old_fs); |
| } |
| |
| static void dump_file_close(struct dump_file *dump_file_fp) |
| { |
| if (dump_file_fp->file_fp) { |
| vfs_fsync(dump_file_fp->file_fp, 0); |
| filp_close(dump_file_fp->file_fp, current->files); |
| dump_file_fp->file_fp = NULL; |
| } |
| } |
| |
| struct out_elem *_find_free_elem(void) |
| { |
| int i = 0; |
| |
| for (i = 0; i < MAX_OUT_ELEM_NUM; i++) { |
| struct out_elem *pout = &out_elem_table[i]; |
| |
| if (!pout->used) |
| return pout; |
| } |
| return NULL; |
| } |
| |
| static struct pid_entry *_malloc_pid_entry_slot(int sid, int pid) |
| { |
| int i = 0; |
| int start = 0; |
| int end = 0; |
| struct pid_entry *pid_slot; |
| int j = 0; |
| int jump = 0; |
| int row_start = 0; |
| |
| if (sid >= MAX_SID_NUM) { |
| pr_dbg("%s error sid:%d\n", __func__, sid); |
| return NULL; |
| } |
| |
| start = sid_table[sid].pid_entry_begin; |
| end = sid_table[sid].pid_entry_begin + sid_table[sid].pid_entry_num; |
| |
| for (i = start; i < end; i++) { |
| if (i >= MAX_TS_PID_NUM) { |
| pr_dbg("err sid:%d,pid start:%d, num:%d\n", sid, |
| sid_table[sid].pid_entry_begin, |
| sid_table[sid].pid_entry_num); |
| return NULL; |
| } |
| |
| pid_slot = &pid_table[i]; |
| |
| if (!pid_slot->used) { |
| /*check same pid, not at same row(there are 4 pid) */ |
| row_start = i / 4 * 4; |
| for (j = row_start; j < row_start + 4; j++) { |
| if (pid_table[j].used && |
| pid_table[j].pid == pid) { |
| jump = 1; |
| break; |
| } |
| } |
| if (jump) { |
| pr_dbg("sid:%d at pos:%d, find pid:%d\n", |
| sid, j, pid); |
| jump = 0; |
| continue; |
| } |
| pr_dbg("sid:%d start:%d, end:%d, pid_entry:%d\n", sid, |
| start, end, pid_slot->id); |
| return pid_slot; |
| } |
| } |
| pr_dbg("err sid:%d,pid start:%d, num:%d\n", sid, |
| sid_table[sid].pid_entry_begin, sid_table[sid].pid_entry_num); |
| |
| return NULL; |
| } |
| |
| static int _free_pid_entry_slot(struct pid_entry *pid_slot) |
| { |
| if (pid_slot) { |
| pid_slot->pid = -1; |
| pid_slot->pid_mask = 0; |
| pid_slot->used = 0; |
| } |
| return 0; |
| } |
| |
| static struct es_entry *_malloc_es_entry_slot(void) |
| { |
| int i = 0; |
| |
| for (i = 0; i < MAX_ES_NUM; i++) { |
| struct es_entry *p = &es_table[i]; |
| |
| if (p->used == 0) { |
| p->used = 1; |
| return p; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| static int _free_es_entry_slot(struct es_entry *es) |
| { |
| if (es) { |
| es->pid = 0; |
| es->status = -1; |
| es->used = 0; |
| es->buff_id = 0; |
| } |
| return 0; |
| } |
| |
| static int _check_timer_wakeup(void) |
| { |
| if (timer_wake_up) { |
| timer_wake_up = 0; |
| return 1; |
| } |
| return 0; |
| } |
| |
| static void _timer_ts_out_func(unsigned long arg) |
| { |
| // dprint("wakeup ts_out_timer\n"); |
| if (ts_out_task_tmp.ts_out_list) { |
| timer_wake_up = 1; |
| wake_up_interruptible(&ts_out_task_tmp.wait_queue); |
| mod_timer(&ts_out_task_tmp.out_timer, |
| jiffies + msecs_to_jiffies(out_flush_time)); |
| } |
| } |
| |
| static int _check_timer_es_wakeup(void) |
| { |
| if (timer_es_wake_up) { |
| timer_es_wake_up = 0; |
| return 1; |
| } |
| return 0; |
| } |
| |
| static void _timer_es_out_func(unsigned long arg) |
| { |
| // dprint("wakeup ts_out_timer\n"); |
| if (es_out_task_tmp.ts_out_list) { |
| timer_es_wake_up = 1; |
| wake_up_interruptible(&es_out_task_tmp.wait_queue); |
| mod_timer(&es_out_task_tmp.out_timer, |
| jiffies + msecs_to_jiffies(out_es_flush_time)); |
| } |
| } |
| |
| static int out_sec_cb_list(struct out_elem *pout, char *buf, int size) |
| { |
| int w_size = 0; |
| int last_w_size = -1; |
| struct cb_entry *ptmp = NULL; |
| |
| if (pout->running != TASK_RUNNING) |
| return 0; |
| |
| ptmp = pout->cb_sec_list; |
| while (ptmp && ptmp->cb) { |
| w_size = ptmp->cb(pout, buf, size, ptmp->udata[0], 0, 0); |
| if (last_w_size != -1 && w_size != last_w_size) { |
| dprint("ref:%d ", pout->ref); |
| dprint("add pid:%d cache for filter ", |
| pout->pid_list->pid); |
| dprint("w:%d,last_w:%d\n", w_size, last_w_size); |
| } |
| last_w_size = w_size; |
| ptmp = ptmp->next; |
| } |
| |
| return w_size; |
| } |
| |
| static int out_ts_cb_list(struct out_elem *pout, char *buf, int size, |
| int req_len, int *req_ret) |
| { |
| int w_size = 0; |
| struct cb_entry *ptmp = NULL; |
| |
| if (pout->running != TASK_RUNNING) |
| return 0; |
| |
| ptmp = pout->cb_ts_list; |
| while (ptmp && ptmp->cb) { |
| w_size = ptmp->cb(pout, buf, size, ptmp->udata[0], |
| req_len, req_ret); |
| if (req_ret && *req_ret == 1) |
| return 0; |
| ptmp = ptmp->next; |
| } |
| |
| return w_size; |
| } |
| |
| static int section_process(struct out_elem *pout) |
| { |
| int ret = 0; |
| int len = 0, w_size; |
| char *pread; |
| |
| if (pout->pchan->sec_level) |
| start_aucpu_non_es(pout); |
| |
| if (pout->remain_len == 0) { |
| len = MAX_READ_BUF_LEN; |
| if (pout->pchan->sec_level) |
| ret = aucpu_bufferid_read(pout, &pread, len, 0); |
| else |
| ret = SC2_bufferid_read(pout->pchan, &pread, len, 0); |
| if (ret != 0) { |
| if (pout->cb_sec_list) { |
| w_size = out_sec_cb_list(pout, pread, ret); |
| pr_dbg("%s send:%d, w:%d wwwwww\n", __func__, |
| ret, w_size); |
| pout->remain_len = ret - w_size; |
| if (pout->remain_len) { |
| if (pout->remain_len >= |
| READ_CACHE_SIZE) { |
| dprint("len:%d lost data\n", |
| pout->remain_len); |
| pout->remain_len = 0; |
| } else { |
| memcpy(pout->cache, |
| pread + w_size, |
| pout->remain_len); |
| } |
| } |
| } |
| if (pout->cb_ts_list) |
| out_ts_cb_list(pout, pread, ret, 0, 0); |
| } |
| } else { |
| len = READ_CACHE_SIZE - pout->remain_len; |
| if (pout->pchan->sec_level) |
| ret = aucpu_bufferid_read(pout, &pread, len, 0); |
| else |
| ret = SC2_bufferid_read(pout->pchan, &pread, len, 0); |
| if (ret != 0) { |
| memcpy(pout->cache + pout->remain_len, pread, ret); |
| pout->remain_len += ret; |
| if (ret == len) { |
| ret = pout->remain_len; |
| w_size = |
| out_sec_cb_list(pout, pout->cache, ret); |
| pr_dbg("%s send:%d, w:%d\n", __func__, ret, |
| w_size); |
| pout->remain_len = ret - w_size; |
| if (pout->remain_len) |
| memmove(pout->cache, |
| pout->cache + w_size, |
| pout->remain_len); |
| } |
| if (pout->cb_ts_list) |
| out_ts_cb_list(pout, pread, ret, 0, 0); |
| } |
| } |
| return 0; |
| } |
| |
| static void write_sec_ts_data(struct out_elem *pout, char *buf, int size) |
| { |
| struct dmx_sec_ts_data sec_ts_data; |
| |
| sec_ts_data.buf_start = pout->pchan->mem_phy; |
| sec_ts_data.buf_end = sec_ts_data.buf_start + pout->pchan->mem_size; |
| sec_ts_data.data_start = (unsigned long)buf; |
| sec_ts_data.data_end = (unsigned long)buf + size; |
| |
| out_ts_cb_list(pout, (char *)&sec_ts_data, |
| sizeof(struct dmx_sec_ts_data), 0, 0); |
| } |
| |
| static int dvr_process(struct out_elem *pout) |
| { |
| int ret = 0; |
| int len = 0; |
| char *pread; |
| int flag = 0; |
| |
| if (pout->pchan->sec_level) |
| flag = 1; |
| |
| len = MAX_DVR_READ_BUF_LEN; |
| ret = SC2_bufferid_read(pout->pchan, &pread, len, flag); |
| if (ret != 0) { |
| if (pout->cb_ts_list && flag == 0) { |
| // dprint("%s w:%d wwwwww\n", __func__, len); |
| out_ts_cb_list(pout, pread, ret, 0, 0); |
| if (dump_dvr_ts == 1) { |
| dump_file_open(DVR_DUMP_FILE, &dvr_dump_file, |
| 0, 0, 1); |
| dump_file_write(pread, ret, &dvr_dump_file); |
| } else { |
| dump_file_close(&dvr_dump_file); |
| } |
| } else if (pout->cb_ts_list && flag == 1) { |
| write_sec_ts_data(pout, pread, ret); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int _task_out_func(void *data) |
| { |
| int timeout = 0; |
| int ret = 0; |
| int len = 0; |
| struct ts_out *ptmp; |
| char *pread = NULL; |
| |
| while (ts_out_task_tmp.running == TASK_RUNNING) { |
| timeout = |
| wait_event_interruptible(ts_out_task_tmp.wait_queue, |
| _check_timer_wakeup()); |
| |
| if (ts_out_task_tmp.running != TASK_RUNNING) |
| break; |
| |
| mutex_lock(ts_output_mutex); |
| |
| ptmp = ts_out_task_tmp.ts_out_list; |
| while (ptmp) { |
| if (!ptmp->pout->enable) { |
| ptmp = ptmp->pnext; |
| continue; |
| } |
| if (ptmp->pout->format == SECTION_FORMAT) { |
| section_process(ptmp->pout); |
| } else if (ptmp->pout->format == DVR_FORMAT) { |
| dvr_process(ptmp->pout); |
| } else { |
| len = MAX_READ_BUF_LEN; |
| if (ptmp->pout->pchan->sec_level) { |
| start_aucpu_non_es(ptmp->pout); |
| ret = aucpu_bufferid_read( |
| ptmp->pout, &pread, len, 0); |
| } else { |
| ret = SC2_bufferid_read( |
| ptmp->pout->pchan, &pread, len, 0); |
| } |
| if (ret != 0) |
| out_ts_cb_list(ptmp->pout, pread, |
| ret, 0, 0); |
| } |
| ptmp = ptmp->pnext; |
| } |
| mutex_unlock(ts_output_mutex); |
| } |
| ts_out_task_tmp.running = TASK_IDLE; |
| return 0; |
| } |
| |
| static int _task_es_out_func(void *data) |
| { |
| int timeout = 0; |
| struct ts_out *ptmp; |
| int ret = 0; |
| |
| while (es_out_task_tmp.running == TASK_RUNNING) { |
| timeout = |
| wait_event_interruptible(es_out_task_tmp.wait_queue, |
| _check_timer_es_wakeup()); |
| |
| if (es_out_task_tmp.running != TASK_RUNNING) |
| break; |
| |
| mutex_lock(&es_output_mutex); |
| |
| ptmp = es_out_task_tmp.ts_out_list; |
| while (ptmp) { |
| if (!ptmp->pout->enable) { |
| ptmp = ptmp->pnext; |
| continue; |
| } |
| if (ptmp->pout->format == ES_FORMAT) { |
| // pr_dbg("get %s data\n", |
| // ptmp->pout->type == AUDIO_TYPE ? |
| // "audio" : "video"); |
| do { |
| ret = |
| _handle_es(ptmp->pout, |
| ptmp->es_params); |
| } while (ret == 0); |
| // pr_dbg("get %s data done\n", |
| // ptmp->pout->type == AUDIO_TYPE ? |
| // "audio" : "video"); |
| } |
| ptmp = ptmp->pnext; |
| } |
| mutex_unlock(&es_output_mutex); |
| } |
| es_out_task_tmp.running = TASK_IDLE; |
| return 0; |
| } |
| |
| //> 0: have dirty data |
| //0: success |
| //-1: exit |
| //-2: pid not same |
| static int get_non_sec_es_header(struct out_elem *pout, char *last_header, |
| char *cur_header, |
| struct dmx_non_sec_es_header *pheader) |
| { |
| char *pts_dts = NULL; |
| int ret = 0; |
| int header_len = 0; |
| int offset = 0; |
| int pid = 0; |
| unsigned int cur_es_bytes = 0; |
| unsigned int last_es_bytes = 0; |
| |
| // pr_dbg("%s enter\n", __func__); |
| // pr_dbg("%s pid:0x%0x\n", __func__, pout->es_pes->pid); |
| |
| header_len = 16; |
| offset = 0; |
| |
| if (!pout->aucpu_pts_start && |
| pout->aucpu_pts_handle >= 0) { |
| if (wdma_get_active(pout->pchan1->id)) { |
| ret = aml_aucpu_strm_start(pout->aucpu_pts_handle); |
| if (ret >= 0) { |
| pr_dbg("aucpu pts start success\n"); |
| pout->aucpu_pts_start = 1; |
| } else { |
| pr_dbg("aucpu start fail ret:%d\n", |
| ret); |
| return -1; |
| } |
| } else { |
| return -1; |
| } |
| } |
| |
| while (header_len) { |
| if (pout->aucpu_pts_start) |
| ret = aucpu_bufferid_read(pout, &pts_dts, |
| header_len, 1); |
| else |
| ret = SC2_bufferid_read(pout->pchan1, |
| &pts_dts, header_len, 0); |
| if (ret != 0) { |
| memcpy((char *)(cur_header + offset), pts_dts, ret); |
| header_len -= ret; |
| offset += ret; |
| } else { |
| return -3; |
| } |
| if (pout->running == TASK_DEAD) |
| return -1; |
| } |
| pid = (cur_header[1] & 0x1f) << 8 | cur_header[0]; |
| if (pout->es_pes->pid != pid) { |
| dprint("%s pid diff req pid %d, ret pid:%d\n", |
| __func__, pout->es_pes->pid, pid); |
| return -2; |
| } |
| pr_dbg("cur header: 0x%0x 0x%0x 0x%0x 0x%0x\n", |
| *(unsigned int *)cur_header, |
| *((unsigned int *)cur_header + 1), |
| *((unsigned int *)cur_header + 2), |
| *((unsigned int *)cur_header + 3)); |
| |
| pr_dbg("last header: 0x%0x 0x%0x 0x%0x 0x%0x\n", |
| *(unsigned int *)last_header, |
| *((unsigned int *)last_header + 1), |
| *((unsigned int *)last_header + 2), |
| *((unsigned int *)last_header + 3)); |
| |
| cur_es_bytes = cur_header[7] << 24 | |
| cur_header[6] << 16 | cur_header[5] << 8 | cur_header[4]; |
| |
| //when start, es_bytes not equal 0, there are dirty data |
| if (last_header[0] == 0xff && last_header[1] == 0xff) { |
| pr_dbg("%s dirty data:%d\n", __func__, cur_es_bytes); |
| if (cur_es_bytes != 0) |
| return cur_es_bytes; |
| } |
| |
| pheader->pts_dts_flag = last_header[2] & 0x3; |
| pheader->dts = last_header[3] & 0x1; |
| pheader->dts <<= 32; |
| pheader->dts |= last_header[11] << 24 |
| | last_header[10] << 16 | last_header[9] << 8 | last_header[8]; |
| pheader->pts = last_header[3] >> 1 & 0x1; |
| pheader->pts <<= 32; |
| pheader->pts |= last_header[15] << 24 |
| | last_header[14] << 16 | last_header[13] << 8 | last_header[12]; |
| |
| pheader->pts &= 0x1FFFFFFFF; |
| last_es_bytes = last_header[7] << 24 |
| | last_header[6] << 16 | last_header[5] << 8 | last_header[4]; |
| if (cur_es_bytes < last_es_bytes) |
| pheader->len = 0xffffffff - last_es_bytes + cur_es_bytes; |
| else |
| pheader->len = cur_es_bytes - last_es_bytes; |
| |
| pr_dbg("%s len:%d,cur_es_bytes:0x%0x, last_es_bytes:0x%0x\n", |
| __func__, pheader->len, cur_es_bytes, last_es_bytes); |
| pr_dbg("%s pid:0x%0x\n", __func__, pout->es_pes->pid); |
| |
| return 0; |
| } |
| |
| static int write_es_data(struct out_elem *pout, struct es_params_t *es_params) |
| { |
| int ret; |
| char *ptmp; |
| int len; |
| int h_len = sizeof(struct dmx_non_sec_es_header); |
| int es_len = 0; |
| |
| if (es_params->have_header == 0) |
| return -1; |
| |
| if (es_params->have_send_header == 0) { |
| pr_dbg("%s pdts_flag:%d, pts:0x%lx, dts:0x%lx, len:%d\n", |
| pout->type == AUDIO_TYPE ? "audio" : "video", |
| es_params->header.pts_dts_flag, |
| (unsigned long)es_params->header.pts, |
| (unsigned long)es_params->header.dts, |
| es_params->header.len); |
| if (es_params->header.pts_dts_flag & 0x2) |
| pout->newest_pts = es_params->header.pts; |
| out_ts_cb_list(pout, (char *)&es_params->header, h_len, |
| (h_len + es_params->header.len), |
| &es_params->es_overflow); |
| es_params->have_send_header = 1; |
| } |
| |
| es_len = es_params->header.len; |
| len = es_len - es_params->data_len; |
| ret = SC2_bufferid_read(pout->pchan, &ptmp, len, 0); |
| if (ret) { |
| if (!es_params->es_overflow) |
| out_ts_cb_list(pout, ptmp, ret, 0, 0); |
| else |
| pr_dbg("audio data lost\n"); |
| if (((dump_audio_es & 0xFFFF) == pout->es_pes->pid && |
| ((dump_audio_es >> 16) & 0xFFFF) == pout->sid) || |
| dump_audio_es == 0xFFFFFFFF) |
| dump_file_open(AUDIOES_DUMP_FILE, &pout->dump_file, |
| pout->sid, pout->es_pes->pid, 0); |
| if (pout->dump_file.file_fp && dump_audio_es == 0) |
| dump_file_close(&pout->dump_file); |
| if (pout->dump_file.file_fp) |
| dump_file_write(ptmp, ret, &pout->dump_file); |
| |
| es_params->data_len += ret; |
| pr_dbg("%s total len:%d, remain:%d\n", |
| pout->type == AUDIO_TYPE ? "audio" : "video", |
| es_len, |
| es_len - es_params->data_len); |
| |
| if (ret != len) { |
| if (pout->pchan->r_offset != 0) |
| return -1; |
| /*loop back ,read one time*/ |
| len = es_params->header.len - es_params->data_len; |
| ret = SC2_bufferid_read(pout->pchan, &ptmp, len, 0); |
| if (ret) { |
| if (!es_params->es_overflow) |
| out_ts_cb_list(pout, ptmp, ret, 0, 0); |
| else |
| pr_dbg("audio data lost\n"); |
| if (pout->dump_file.file_fp) |
| dump_file_write( |
| ptmp, ret, &pout->dump_file); |
| es_params->data_len += ret; |
| pr_dbg("%s total len:%d, remain:%d\n", |
| pout->type == AUDIO_TYPE ? |
| "audio" : "video", |
| es_len, |
| es_len - es_params->data_len); |
| if (ret != len) |
| return -1; |
| else |
| return 0; |
| } |
| } else { |
| return 0; |
| } |
| } |
| return -1; |
| } |
| |
| static int clean_es_data(struct out_elem *pout, struct chan_id *pchan, |
| unsigned int len) |
| { |
| int ret; |
| char *ptmp; |
| while (len) { |
| ret = SC2_bufferid_read(pout->pchan, &ptmp, len, 0); |
| if (ret != 0) { |
| len -= ret; |
| } |
| if (pout->running == TASK_DEAD) |
| return -1; |
| } |
| return 0; |
| } |
| |
| static int start_aucpu_non_es(struct out_elem *pout) |
| { |
| int ret; |
| |
| if (!pout->aucpu_start && |
| pout->aucpu_handle >= 0 && |
| wdma_get_active(pout->pchan->id)) { |
| ret = aml_aucpu_strm_start(pout->aucpu_handle); |
| if (ret >= 0) { |
| pr_dbg("aucpu start success\n"); |
| pout->aucpu_start = 1; |
| } else { |
| pr_dbg("aucpu start fail ret:%d\n", ret); |
| return -1; |
| } |
| } |
| return 0; |
| } |
| |
| static void create_aucpu_pts(struct out_elem *pout) |
| { |
| struct aml_aucpu_strm_buf src; |
| struct aml_aucpu_strm_buf dst; |
| struct aml_aucpu_inst_config cfg; |
| int ret; |
| |
| if (pout->aucpu_pts_handle < 0 && pout->pchan1->sec_level) { |
| src.phy_start = pout->pchan1->mem_phy; |
| src.buf_size = pout->pchan1->mem_size; |
| src.buf_flags = 0; |
| |
| pr_dbg("%s src aucpu pts phy:0x%lx, size:0x%0x\n", |
| __func__, src.phy_start, src.buf_size); |
| |
| pout->aucpu_pts_mem_size = pout->pchan1->mem_size; |
| ret = |
| _alloc_buff(pout->aucpu_pts_mem_size, 0, |
| &pout->aucpu_pts_mem, |
| &pout->aucpu_pts_mem_phy, 0); |
| if (ret != 0) |
| return; |
| pr_dbg("%s dst aucpu pts mem:0x%lx, phy:0x%lx\n", |
| __func__, pout->aucpu_pts_mem, pout->aucpu_pts_mem_phy); |
| |
| dst.phy_start = pout->aucpu_pts_mem_phy; |
| dst.buf_size = pout->aucpu_pts_mem_size; |
| dst.buf_flags = 0; |
| cfg.media_type = MEDIA_PTS_PACK; |
| cfg.dma_chn_id = (pout->es_pes->pid << 8) | |
| pout->pchan1->id; |
| cfg.config_flags = 0; |
| pout->aucpu_pts_handle = aml_aucpu_strm_create(&src, |
| &dst, &cfg); |
| if (pout->aucpu_pts_handle < 0) |
| dprint("%s create aucpu pts fail, ret:%d\n", |
| __func__, pout->aucpu_pts_handle); |
| else |
| dprint("%s create aucpu pts inst success\n", __func__); |
| |
| pout->aucpu_pts_r_offset = 0; |
| pout->aucpu_pts_start = 0; |
| } |
| } |
| |
| static void create_aucpu_inst(struct out_elem *pout) |
| { |
| struct aml_aucpu_strm_buf src; |
| struct aml_aucpu_strm_buf dst; |
| struct aml_aucpu_inst_config cfg; |
| int ret; |
| |
| if (pout->type == NONE_TYPE) |
| return; |
| |
| if (pout->type == VIDEO_TYPE) { |
| create_aucpu_pts(pout); |
| return; |
| } else if (pout->type == AUDIO_TYPE) { |
| create_aucpu_pts(pout); |
| } |
| /*now except the video, others will pass by aucpu */ |
| if (pout->aucpu_handle < 0) { |
| src.phy_start = pout->pchan->mem_phy; |
| src.buf_size = pout->pchan->mem_size; |
| src.buf_flags = 0; |
| |
| pr_dbg("%s src aucpu phy:0x%lx, size:0x%0x\n", |
| __func__, src.phy_start, src.buf_size); |
| |
| pout->aucpu_mem_size = pout->pchan->mem_size; |
| ret = |
| _alloc_buff(pout->aucpu_mem_size, 0, &pout->aucpu_mem, |
| &pout->aucpu_mem_phy, 0); |
| if (ret != 0) |
| return; |
| pr_dbg("%s dst aucpu mem:0x%lx, phy:0x%lx\n", |
| __func__, pout->aucpu_mem, pout->aucpu_mem_phy); |
| |
| dst.phy_start = pout->aucpu_mem_phy; |
| dst.buf_size = pout->aucpu_mem_size; |
| dst.buf_flags = 0; |
| cfg.media_type = pout->media_type; /*MEDIA_MPX; */ |
| cfg.dma_chn_id = pout->pchan->id; |
| cfg.config_flags = 0; |
| pout->aucpu_handle = aml_aucpu_strm_create(&src, &dst, &cfg); |
| if (pout->aucpu_handle < 0) |
| dprint("%s create aucpu fail, ret:%d\n", |
| __func__, pout->aucpu_handle); |
| else |
| dprint("%s create aucpu inst success\n", __func__); |
| |
| pout->aucpu_read_offset = 0; |
| pout->aucpu_start = 0; |
| } |
| } |
| |
| static unsigned int aucpu_read_pts_process(struct out_elem *pout, |
| unsigned int w_offset, |
| char **pread, unsigned int len) |
| { |
| unsigned int buf_len = len; |
| unsigned int data_len = 0; |
| |
| pr_dbg("%s pts w:0x%0x, r:0x%0x\n", __func__, |
| (u32)w_offset, (u32)(pout->aucpu_pts_r_offset)); |
| if (w_offset > pout->aucpu_pts_r_offset) { |
| data_len = min((w_offset - pout->aucpu_pts_r_offset), buf_len); |
| if (data_len < 16) |
| return 0; |
| dma_sync_single_for_cpu(aml_get_device(), |
| (dma_addr_t)(pout->aucpu_pts_mem_phy + |
| pout->aucpu_pts_r_offset), |
| data_len, DMA_FROM_DEVICE); |
| *pread = (char *)(pout->aucpu_pts_mem + |
| pout->aucpu_pts_r_offset); |
| pout->aucpu_pts_r_offset += data_len; |
| } else { |
| unsigned int part1_len = 0; |
| |
| part1_len = pout->aucpu_pts_mem_size - pout->aucpu_pts_r_offset; |
| if (part1_len == 0) { |
| data_len = min(w_offset, buf_len); |
| if (data_len < 16) |
| return 0; |
| pout->aucpu_pts_r_offset = 0; |
| *pread = (char *)(pout->aucpu_pts_mem + |
| pout->aucpu_pts_r_offset); |
| dma_sync_single_for_cpu(aml_get_device(), (dma_addr_t) |
| (pout->aucpu_pts_mem_phy + |
| pout->aucpu_pts_r_offset), |
| data_len, DMA_FROM_DEVICE); |
| pout->aucpu_pts_r_offset += data_len; |
| return data_len; |
| } |
| data_len = min(part1_len, buf_len); |
| if (data_len < 16) |
| return 0; |
| |
| *pread = (char *)(pout->aucpu_pts_mem + |
| pout->aucpu_pts_r_offset); |
| if (data_len < part1_len) { |
| dma_sync_single_for_cpu(aml_get_device(), (dma_addr_t) |
| (pout->aucpu_pts_mem_phy + |
| pout->aucpu_pts_r_offset), |
| data_len, DMA_FROM_DEVICE); |
| pout->aucpu_pts_r_offset += data_len; |
| } else { |
| data_len = part1_len; |
| dma_sync_single_for_cpu(aml_get_device(), (dma_addr_t) |
| (pout->aucpu_pts_mem_phy + |
| pout->aucpu_pts_r_offset), |
| data_len, DMA_FROM_DEVICE); |
| pout->aucpu_pts_r_offset = 0; |
| } |
| } |
| pr_dbg("%s pts request:%d, ret:%d\n", __func__, len, data_len); |
| return data_len; |
| } |
| |
| static unsigned int aucpu_read_process(struct out_elem *pout, |
| unsigned int w_offset, |
| char **pread, unsigned int len, |
| int is_pts) |
| { |
| unsigned int buf_len = len; |
| unsigned int data_len = 0; |
| |
| if (is_pts) |
| return aucpu_read_pts_process(pout, w_offset, pread, len); |
| |
| pr_dbg("%s w:0x%0x, r:0x%0x\n", __func__, |
| (u32)w_offset, (u32)(pout->aucpu_read_offset)); |
| if (w_offset > pout->aucpu_read_offset) { |
| data_len = min((w_offset - pout->aucpu_read_offset), buf_len); |
| dma_sync_single_for_cpu(aml_get_device(), |
| (dma_addr_t)(pout->aucpu_mem_phy + |
| pout->aucpu_read_offset), |
| data_len, DMA_FROM_DEVICE); |
| *pread = (char *)(pout->aucpu_mem + pout->aucpu_read_offset); |
| pout->aucpu_read_offset += data_len; |
| } else { |
| unsigned int part1_len = 0; |
| |
| part1_len = pout->aucpu_mem_size - pout->aucpu_read_offset; |
| if (part1_len == 0) { |
| data_len = min(w_offset, buf_len); |
| pout->aucpu_read_offset = 0; |
| *pread = (char *)(pout->aucpu_mem + |
| pout->aucpu_read_offset); |
| dma_sync_single_for_cpu(aml_get_device(), (dma_addr_t) |
| (pout->aucpu_mem_phy + |
| pout->aucpu_read_offset), |
| data_len, DMA_FROM_DEVICE); |
| pout->aucpu_read_offset += data_len; |
| return data_len; |
| } |
| data_len = min(part1_len, buf_len); |
| *pread = (char *)(pout->aucpu_mem + pout->aucpu_read_offset); |
| if (data_len < part1_len) { |
| dma_sync_single_for_cpu(aml_get_device(), (dma_addr_t) |
| (pout->aucpu_mem_phy + |
| pout->aucpu_read_offset), |
| data_len, DMA_FROM_DEVICE); |
| pout->aucpu_read_offset += data_len; |
| } else { |
| data_len = part1_len; |
| dma_sync_single_for_cpu(aml_get_device(), (dma_addr_t) |
| (pout->aucpu_mem_phy + |
| pout->aucpu_read_offset), |
| data_len, DMA_FROM_DEVICE); |
| pout->aucpu_read_offset = 0; |
| } |
| } |
| pr_dbg("%s request:%d, ret:%d\n", __func__, len, data_len); |
| return data_len; |
| } |
| |
| static int aucpu_bufferid_read(struct out_elem *pout, |
| char **pread, unsigned int len, int is_pts) |
| { |
| struct aml_aucpu_buf_upd upd; |
| unsigned int w_offset = 0; |
| s32 handle; |
| unsigned long mem_phy; |
| unsigned int r_offset; |
| |
| if (is_pts) { |
| handle = pout->aucpu_pts_handle; |
| mem_phy = pout->aucpu_pts_mem_phy; |
| r_offset = pout->aucpu_pts_r_offset; |
| } else { |
| handle = pout->aucpu_handle; |
| mem_phy = pout->aucpu_mem_phy; |
| r_offset = pout->aucpu_read_offset; |
| } |
| |
| if (aml_aucpu_strm_get_dst(handle, &upd) |
| >= 0) { |
| w_offset = upd.phy_cur_ptr - mem_phy; |
| if (r_offset != w_offset) |
| return aucpu_read_process(pout, |
| w_offset, pread, len, is_pts); |
| } |
| return 0; |
| } |
| |
| static int write_aucpu_es_data(struct out_elem *pout, |
| struct es_params_t *es_params, unsigned int isdirty) |
| { |
| int ret; |
| char *ptmp; |
| int h_len = sizeof(struct dmx_non_sec_es_header); |
| int es_len = 0; |
| int len = 0; |
| |
| pr_dbg("%s chan id:%d, isdirty:%d\n", __func__, |
| pout->pchan->id, isdirty); |
| |
| if (es_params->have_header == 0) |
| return -1; |
| |
| if (!pout->aucpu_start && |
| pout->format == ES_FORMAT && |
| pout->type == AUDIO_TYPE && pout->aucpu_handle >= 0) { |
| if (wdma_get_active(pout->pchan->id)) { |
| ret = aml_aucpu_strm_start(pout->aucpu_handle); |
| if (ret >= 0) { |
| pr_dbg("aucpu start success\n"); |
| pout->aucpu_start = 1; |
| } else { |
| pr_dbg("aucpu start fail ret:%d\n", |
| ret); |
| return -1; |
| } |
| } else { |
| return -1; |
| } |
| } |
| |
| if (es_params->have_send_header == 0) { |
| pr_dbg("%s pdts_flag:%d, pts:0x%lx, dts:0x%lx, len:%d\n", |
| pout->type == AUDIO_TYPE ? "audio" : "video", |
| es_params->header.pts_dts_flag, |
| (unsigned long)es_params->header.pts, |
| (unsigned long)es_params->header.dts, |
| es_params->header.len); |
| if (es_params->header.pts_dts_flag & 0x2) |
| pout->newest_pts = es_params->header.pts; |
| out_ts_cb_list(pout, (char *)&es_params->header, h_len, |
| (h_len + es_params->header.len), |
| &es_params->es_overflow); |
| es_params->have_send_header = 1; |
| } |
| |
| es_len = es_params->header.len; |
| len = es_len - es_params->data_len; |
| ret = aucpu_bufferid_read(pout, &ptmp, len, 0); |
| if (ret) { |
| if (!es_params->es_overflow) |
| out_ts_cb_list(pout, ptmp, ret, 0, 0); |
| else |
| pr_dbg("audio data lost\n"); |
| if (((dump_audio_es & 0xFFFF) == pout->es_pes->pid && |
| ((dump_audio_es >> 16) & 0xFFFF) == pout->sid) || |
| dump_audio_es == 0xFFFFFFFF) |
| dump_file_open(AUDIOES_DUMP_FILE, &pout->dump_file, |
| pout->sid, pout->es_pes->pid, 0); |
| |
| if (pout->dump_file.file_fp && dump_audio_es == 0) |
| dump_file_close(&pout->dump_file); |
| |
| if (pout->dump_file.file_fp) |
| dump_file_write(ptmp, ret, &pout->dump_file); |
| |
| es_params->data_len += ret; |
| pr_dbg("%s total len:%d, remain:%d\n", |
| pout->type == AUDIO_TYPE ? "audio" : "video", |
| es_len, |
| es_len - es_params->data_len); |
| |
| if (ret != len) |
| return -1; |
| else |
| return 0; |
| } |
| return -1; |
| } |
| |
| static int write_aucpu_sec_es_data(struct out_elem *pout, |
| struct es_params_t *es_params) |
| { |
| unsigned int len = es_params->header.len; |
| struct dmx_sec_es_data sec_es_data; |
| char *ptmp; |
| int ret; |
| |
| if (es_params->header.len == 0) |
| return -1; |
| |
| if (!pout->aucpu_start && |
| pout->format == ES_FORMAT && |
| pout->type == AUDIO_TYPE && pout->aucpu_handle >= 0) { |
| if (wdma_get_active(pout->pchan->id)) { |
| ret = aml_aucpu_strm_start(pout->aucpu_handle); |
| if (ret >= 0) { |
| pr_dbg("aucpu start success\n"); |
| pout->aucpu_start = 1; |
| } else { |
| pr_dbg("aucpu start fail ret:%d\n", |
| ret); |
| return -1; |
| } |
| } else { |
| return -1; |
| } |
| } |
| |
| len = es_params->header.len - es_params->data_len; |
| ret = aucpu_bufferid_read(pout, &ptmp, len, 0); |
| if (es_params->data_start == 0) |
| es_params->data_start = (unsigned long)ptmp; |
| |
| es_params->data_len += ret; |
| if (ret != len) |
| return -1; |
| |
| memset(&sec_es_data, 0, sizeof(struct dmx_sec_es_data)); |
| sec_es_data.pts_dts_flag = es_params->header.pts_dts_flag; |
| sec_es_data.dts = es_params->header.dts; |
| sec_es_data.pts = es_params->header.pts; |
| sec_es_data.buf_start = pout->pchan->mem; |
| sec_es_data.buf_end = pout->pchan->mem + pout->pchan->mem_size; |
| sec_es_data.data_start = es_params->data_start; |
| sec_es_data.data_end = (unsigned long)ptmp + len; |
| |
| pr_dbg("video data start:0x%x, end:0x%x\n", |
| sec_es_data.data_start, sec_es_data.data_end); |
| pr_dbg("video pdts_flag:%d, pts:0x%lx, dts:0x%lx, offset:0x%lx\n", |
| sec_es_data.pts_dts_flag, (unsigned long)sec_es_data.pts, |
| (unsigned long)sec_es_data.dts, |
| (unsigned long)(sec_es_data.data_start - sec_es_data.buf_start)); |
| |
| out_ts_cb_list(pout, (char *)&sec_es_data, |
| sizeof(struct dmx_sec_es_data), 0, 0); |
| |
| es_params->data_start = 0; |
| es_params->data_len = 0; |
| return 0; |
| } |
| |
| static int clean_aucpu_data(struct out_elem *pout, unsigned int len) |
| { |
| int ret; |
| char *ptmp; |
| |
| if (pout->aucpu_handle < 0) |
| return -1; |
| |
| if (!pout->aucpu_start && |
| pout->format == ES_FORMAT && |
| pout->type == AUDIO_TYPE && pout->aucpu_handle >= 0) { |
| if (wdma_get_active(pout->pchan->id)) { |
| ret = aml_aucpu_strm_start(pout->aucpu_handle); |
| if (ret >= 0) { |
| pr_dbg("aucpu start success\n"); |
| pout->aucpu_start = 1; |
| } else { |
| pr_dbg("aucpu start fail ret:%d\n", |
| ret); |
| return -1; |
| } |
| } |
| } |
| |
| while (len) { |
| ret = aucpu_bufferid_read(pout, &ptmp, len, 0); |
| if (ret != 0) |
| len -= ret; |
| |
| if (pout->running == TASK_DEAD) |
| return -1; |
| } |
| return 0; |
| } |
| |
| static void enforce_flush_cache(char *addr, unsigned int len) |
| { |
| if (len == 0) |
| return; |
| dma_sync_single_for_cpu( |
| aml_get_device(), |
| (dma_addr_t)(addr), |
| len, DMA_FROM_DEVICE); |
| } |
| |
| static int write_sec_video_es_data(struct out_elem *pout, |
| struct es_params_t *es_params) |
| { |
| unsigned int len = es_params->header.len; |
| struct dmx_sec_es_data sec_es_data; |
| char *ptmp; |
| int ret; |
| int flag = 0; |
| |
| pr_dbg("%s pid:0x%0x enter\n", __func__, pout->es_pes->pid); |
| if (es_params->header.len == 0) |
| return -1; |
| |
| if (pout->pchan->sec_level) |
| flag = 1; |
| len = es_params->header.len - es_params->data_len; |
| ret = SC2_bufferid_read(pout->pchan, &ptmp, len, flag); |
| if (ret == 0) |
| return -1; |
| |
| if (es_params->data_start == 0) |
| es_params->data_start = (unsigned long)ptmp; |
| |
| es_params->data_len += ret; |
| |
| if (((dump_video_es & 0xFFFF) == pout->es_pes->pid && |
| ((dump_video_es >> 16) & 0xFFFF) == pout->sid) || |
| dump_video_es == 0XFFFFFFFF) |
| dump_file_open(VIDEOES_DUMP_FILE, &pout->dump_file, |
| pout->sid, pout->es_pes->pid, 0); |
| |
| if (pout->dump_file.file_fp && dump_video_es == 0) |
| dump_file_close(&pout->dump_file); |
| |
| if (pout->dump_file.file_fp) { |
| if (flag) { |
| enforce_flush_cache(ptmp, ret); |
| dump_file_write( |
| ptmp - pout->pchan->mem_phy + |
| pout->pchan->mem, ret, |
| &pout->dump_file); |
| } else { |
| dump_file_write(ptmp, ret, &pout->dump_file); |
| } |
| } |
| |
| if (ret != len) { |
| // if (pout->pchan->r_offset != 0) |
| // return -1; |
| |
| /*if loop back , read one time */ |
| len = es_params->header.len - es_params->data_len; |
| ret = SC2_bufferid_read(pout->pchan, &ptmp, len, flag); |
| if (ret != 0) { |
| es_params->data_len += ret; |
| |
| if (pout->dump_file.file_fp) { |
| if (flag) { |
| enforce_flush_cache(ptmp, ret); |
| dump_file_write(ptmp - |
| pout->pchan->mem_phy + |
| pout->pchan->mem, ret, |
| &pout->dump_file); |
| } else { |
| dump_file_write(ptmp, ret, |
| &pout->dump_file); |
| } |
| } |
| if (ret != len) |
| dprint("get es len err2, req:%d, actual:%d\n", |
| es_params->header.len, |
| es_params->data_len); |
| } else { |
| len = es_params->data_len; |
| dprint("get es len err1, req:%d, actual:%d\n", |
| es_params->header.len, |
| es_params->data_len); |
| } |
| } |
| memset(&sec_es_data, 0, sizeof(struct dmx_sec_es_data)); |
| sec_es_data.pts_dts_flag = es_params->header.pts_dts_flag; |
| sec_es_data.dts = es_params->header.dts; |
| sec_es_data.pts = es_params->header.pts; |
| sec_es_data.buf_start = pout->pchan->mem_phy; |
| sec_es_data.buf_end = pout->pchan->mem_phy + pout->pchan->mem_size; |
| if (flag) { |
| sec_es_data.data_start = es_params->data_start; |
| sec_es_data.data_end = (unsigned long)ptmp + len; |
| } else { |
| sec_es_data.data_start = es_params->data_start - |
| pout->pchan->mem + pout->pchan->mem_phy; |
| sec_es_data.data_end = (unsigned long)ptmp - |
| pout->pchan->mem + pout->pchan->mem_phy + len; |
| } |
| if (sec_es_data.data_end > sec_es_data.data_start) |
| pr_dbg("video data start:0x%x, end:0x%x len:0x%x\n", |
| sec_es_data.data_start, sec_es_data.data_end, |
| (sec_es_data.data_end - sec_es_data.data_start)); |
| else |
| pr_dbg("video data start:0x%x,data end:0x%x\n", |
| sec_es_data.data_start, sec_es_data.data_end); |
| |
| pr_dbg("video pid:0x%0x sid:0x%0x flag:%d, pts:0x%lx, dts:0x%lx, offset:0x%lx\n", |
| pout->es_pes->pid, |
| pout->sid, |
| sec_es_data.pts_dts_flag, |
| (unsigned long)sec_es_data.pts, |
| (unsigned long)sec_es_data.dts, |
| (unsigned long)(sec_es_data.data_start - |
| sec_es_data.buf_start)); |
| |
| if (es_params->header.pts_dts_flag & 0x2) |
| pout->newest_pts = sec_es_data.pts; |
| out_ts_cb_list(pout, (char *)&sec_es_data, |
| sizeof(struct dmx_sec_es_data), 0, 0); |
| |
| es_params->data_start = 0; |
| es_params->data_len = 0; |
| return 0; |
| } |
| |
| static int _handle_es(struct out_elem *pout, struct es_params_t *es_params) |
| { |
| int ret = 0; |
| unsigned int dirty_len = 0; |
| char cur_header[16]; |
| char *pcur_header; |
| char *plast_header; |
| struct dmx_non_sec_es_header *pheader = &es_params->header; |
| |
| memset(&cur_header, 0, sizeof(cur_header)); |
| pcur_header = (char *)&cur_header; |
| plast_header = (char *)&es_params->last_header; |
| |
| // pr_dbg("enter es %s\n", pout->type ? "audio" : "video"); |
| // pr_dbg("%s enter,line:%d\n", __func__, __LINE__); |
| |
| if (pout->running != TASK_RUNNING) |
| return -1; |
| |
| if (es_params->have_header == 0) { |
| ret = |
| get_non_sec_es_header(pout, plast_header, pcur_header, |
| pheader); |
| if (ret < 0) { |
| return -1; |
| } else if (ret > 0) { |
| dirty_len = ret; |
| if (pout->pchan->sec_level && |
| pout->type != VIDEO_TYPE) |
| ret = clean_aucpu_data(pout, dirty_len); |
| else |
| ret = clean_es_data(pout, |
| pout->pchan, dirty_len); |
| memcpy(&es_params->last_last_header, |
| &es_params->last_header, 16); |
| memcpy(&es_params->last_header, pcur_header, |
| sizeof(es_params->last_header)); |
| dprint("error: clean dirty len:0x%0x\n", dirty_len); |
| return 0; |
| } |
| if (pheader->len == 0) { |
| memcpy(&es_params->last_last_header, |
| &es_params->last_header, 16); |
| memcpy(&es_params->last_header, pcur_header, |
| sizeof(es_params->last_header)); |
| dprint("error: header.len is 0, jump\n"); |
| return 0; |
| } else if (pheader->len >= pout->pchan->mem_size) { |
| memcpy(&es_params->last_last_header, |
| &es_params->last_header, 16); |
| memcpy(&es_params->last_header, pcur_header, |
| sizeof(es_params->last_header)); |
| es_params->header_wp = |
| SC2_bufferid_get_wp_offset(pout->pchan1); |
| dprint("error: es len: 0x%0x\n", pheader->len); |
| es_params->es_error_cn++; |
| return 0; |
| } |
| memcpy(&es_params->last_last_header, |
| &es_params->last_header, 16); |
| memcpy(&es_params->last_header, pcur_header, |
| sizeof(es_params->last_header)); |
| es_params->have_header = 1; |
| } |
| if (debug_ts_output == 2 && es_params->es_error_cn) { |
| int cn = 0; |
| |
| dprint("##############pid:0x%0x\n", |
| pout->es_pes->pid); |
| dprint("es_params header:%d\n", es_params->have_header); |
| dprint("es_params have_send_header:%d\n", |
| es_params->have_send_header); |
| dprint("es_params data_len:%d\n", es_params->data_len); |
| dprint("es_params header len:0x%0x\n", es_params->header.len); |
| dprint("es_params es_error_cn:%d\n", es_params->es_error_cn); |
| dprint("es_params header_wp:0x%0x\n", es_params->header_wp); |
| |
| dprint("get last header:\n"); |
| for (cn = 0; cn < 16; cn++) |
| dprint("0x%0x ", es_params->last_header[cn]); |
| |
| dprint("get last last header:\n"); |
| for (cn = 0; cn < 16; cn++) |
| dprint("0x%0x ", es_params->last_last_header[cn]); |
| |
| dprint("\n#########################\n"); |
| } |
| if (pout->output_mode || pout->pchan->sec_level) { |
| if (es_params->have_header == 0) |
| return -1; |
| |
| if (pout->type == VIDEO_TYPE) { |
| ret = write_sec_video_es_data(pout, es_params); |
| } else { |
| //to do for use aucpu to handle non-video data |
| if (pout->output_mode) { |
| ret = |
| write_aucpu_sec_es_data(pout, es_params); |
| } else { |
| ret = write_aucpu_es_data(pout, es_params, 0); |
| } |
| } |
| if (ret == 0) { |
| es_params->have_header = 0; |
| es_params->have_send_header = 0; |
| es_params->data_len = 0; |
| es_params->data_start = 0; |
| es_params->es_overflow = 0; |
| return 0; |
| } else { |
| return -1; |
| } |
| } else { |
| if (es_params->have_header) { |
| ret = write_es_data(pout, es_params); |
| if (ret == 0) { |
| es_params->have_header = 0; |
| es_params->have_send_header = 0; |
| es_params->data_len = 0; |
| es_params->data_start = 0; |
| es_params->es_overflow = 0; |
| return 0; |
| } else { |
| return -1; |
| } |
| } |
| } |
| return -1; |
| } |
| |
| static void add_ts_out_list(struct ts_out_task *head, struct ts_out *ts_out_tmp) |
| { |
| struct ts_out *cur_tmp = NULL; |
| |
| cur_tmp = head->ts_out_list; |
| while (cur_tmp) { |
| if (!cur_tmp->pnext) |
| break; |
| cur_tmp = cur_tmp->pnext; |
| } |
| if (cur_tmp) |
| cur_tmp->pnext = ts_out_tmp; |
| else |
| head->ts_out_list = ts_out_tmp; |
| } |
| |
| static void remove_ts_out_list(struct out_elem *pout, struct ts_out_task *head) |
| { |
| struct ts_out *ts_out_pre = NULL; |
| struct ts_out *cur_tmp = NULL; |
| |
| cur_tmp = head->ts_out_list; |
| ts_out_pre = cur_tmp; |
| while (cur_tmp) { |
| if (cur_tmp->pout == pout) { |
| if (cur_tmp == head->ts_out_list) |
| head->ts_out_list = cur_tmp->pnext; |
| else |
| ts_out_pre->pnext = cur_tmp->pnext; |
| |
| kfree(cur_tmp->es_params); |
| kfree(cur_tmp); |
| break; |
| } |
| ts_out_pre = cur_tmp; |
| cur_tmp = cur_tmp->pnext; |
| } |
| } |
| |
| /** |
| * ts_output_init |
| * \param sid_num |
| * \param sid_info |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_init(int sid_num, int *sid_info) |
| { |
| int i = 0; |
| struct sid_entry *psid = NULL; |
| int times = 0; |
| struct aml_dvb *advb = aml_get_dvb_device(); |
| |
| do { |
| } while (!tsout_get_ready() && times++ < 20); |
| |
| memset(&sid_table, 0, sizeof(sid_table)); |
| |
| ts_output_max_pid_num_per_sid = MAX_TS_PID_NUM / (sid_num * 4) * 4; |
| |
| for (i = 0; i < sid_num; i++) { |
| psid = &sid_table[sid_info[i]]; |
| psid->used = 1; |
| psid->pid_entry_begin = ts_output_max_pid_num_per_sid * i; |
| psid->pid_entry_num = ts_output_max_pid_num_per_sid; |
| dprint("%s sid:%d,pid start:%d, len:%d\n", |
| __func__, sid_info[i], |
| psid->pid_entry_begin, psid->pid_entry_num); |
| tsout_config_sid_table(sid_info[i], |
| psid->pid_entry_begin / 4, |
| psid->pid_entry_num / 4); |
| } |
| |
| pid_table = vmalloc(sizeof(*pid_table) * MAX_TS_PID_NUM); |
| if (!pid_table) { |
| dprint("%s malloc fail\n", __func__); |
| return -1; |
| } |
| |
| memset(pid_table, 0, sizeof(struct pid_entry) * MAX_TS_PID_NUM); |
| for (i = 0; i < MAX_TS_PID_NUM; i++) { |
| struct pid_entry *pid_slot = &pid_table[i]; |
| |
| pid_slot->id = i; |
| } |
| |
| memset(&es_table, 0, sizeof(es_table)); |
| for (i = 0; i < MAX_ES_NUM; i++) { |
| struct es_entry *es_slot = &es_table[i]; |
| |
| es_slot->id = i; |
| } |
| |
| memset(&remap_table, 0, sizeof(remap_table)); |
| |
| out_elem_table = vmalloc(sizeof(*out_elem_table) |
| * MAX_OUT_ELEM_NUM); |
| if (!out_elem_table) { |
| dprint("%s malloc fail\n", __func__); |
| vfree(pid_table); |
| return -1; |
| } |
| memset(out_elem_table, 0, sizeof(struct out_elem) * MAX_OUT_ELEM_NUM); |
| // memset(&out_elem_table, 0, sizeof(out_elem_table)); |
| memset(&pcr_table, 0, sizeof(pcr_table)); |
| |
| ts_out_task_tmp.running = TASK_RUNNING; |
| ts_out_task_tmp.flush_time_ms = out_flush_time; |
| ts_out_task_tmp.ts_out_list = NULL; |
| ts_output_mutex = &advb->mutex; |
| |
| init_waitqueue_head(&ts_out_task_tmp.wait_queue); |
| ts_out_task_tmp.out_task = |
| kthread_run(_task_out_func, (void *)NULL, "ts_out_task"); |
| if (!ts_out_task_tmp.out_task) |
| dprint("create ts_out_task fail\n"); |
| |
| init_timer(&ts_out_task_tmp.out_timer); |
| ts_out_task_tmp.out_timer.function = _timer_ts_out_func; |
| ts_out_task_tmp.out_timer.data = 0; |
| add_timer(&ts_out_task_tmp.out_timer); |
| |
| es_out_task_tmp.running = TASK_RUNNING; |
| es_out_task_tmp.flush_time_ms = out_es_flush_time; |
| mutex_init(&es_output_mutex); |
| es_out_task_tmp.ts_out_list = NULL; |
| |
| init_waitqueue_head(&es_out_task_tmp.wait_queue); |
| es_out_task_tmp.out_task = |
| kthread_run(_task_es_out_func, (void *)NULL, "es_out_task"); |
| if (!es_out_task_tmp.out_task) |
| dprint("create es_out_task fail\n"); |
| |
| init_timer(&es_out_task_tmp.out_timer); |
| es_out_task_tmp.out_timer.function = _timer_es_out_func; |
| es_out_task_tmp.out_timer.data = 0; |
| add_timer(&es_out_task_tmp.out_timer); |
| |
| return 0; |
| } |
| |
| int ts_output_sid_debug(void) |
| { |
| int i = 0; |
| int dmxdev_num; |
| struct sid_entry *psid = NULL; |
| |
| memset(&sid_table, 0, sizeof(sid_table)); |
| dmxdev_num = 32; |
| /*for every dmx dev, it will use 2 sids, |
| * one is demod, another is local |
| */ |
| ts_output_max_pid_num_per_sid = |
| MAX_TS_PID_NUM / (2 * dmxdev_num * 4) * 4; |
| |
| for (i = 0; i < dmxdev_num; i++) { |
| psid = &sid_table[i]; |
| psid->used = 1; |
| psid->pid_entry_begin = ts_output_max_pid_num_per_sid * 2 * i; |
| psid->pid_entry_num = ts_output_max_pid_num_per_sid; |
| pr_dbg("%s sid:%d,pid start:%d, len:%d\n", |
| __func__, i, psid->pid_entry_begin, psid->pid_entry_num); |
| tsout_config_sid_table(i, |
| psid->pid_entry_begin / 4, |
| psid->pid_entry_num / 4); |
| |
| psid = &sid_table[i + 32]; |
| psid->used = 1; |
| psid->pid_entry_begin = |
| ts_output_max_pid_num_per_sid * (2 * i + 1); |
| psid->pid_entry_num = ts_output_max_pid_num_per_sid; |
| |
| pr_dbg("%s sid:%d, pid start:%d, len:%d\n", __func__, |
| i + 32, psid->pid_entry_begin, psid->pid_entry_num); |
| tsout_config_sid_table(i + 32, |
| psid->pid_entry_begin / 4, |
| psid->pid_entry_num / 4); |
| } |
| |
| return 0; |
| } |
| |
| int ts_output_destroy(void) |
| { |
| if (out_elem_table) |
| vfree(out_elem_table); |
| |
| out_elem_table = NULL; |
| |
| if (pid_table) |
| vfree(pid_table); |
| |
| pid_table = NULL; |
| return 0; |
| } |
| |
| /** |
| * remap pid |
| * \param sid: stream id |
| * \param pid: orginal pid |
| * \param new_pid: replace pid |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_remap_pid(int sid, int pid, int new_pid) |
| { |
| return 0; |
| } |
| |
| /** |
| * set pid pcr |
| * \param sid: stream id |
| * \param pcr_num |
| * \param pcrpid |
| * \retval 0:success. |
| * \retval -1:fail. |
| * \note:pcrpid == -1, it will close |
| */ |
| int ts_output_set_pcr(int sid, int pcr_num, int pcrpid) |
| { |
| pr_dbg("%s pcr_num:%d,pid:%d\n", __func__, pcr_num, pcrpid); |
| if (pcr_num >= MAX_PCR_NUM) { |
| dprint("%s num:%d invalid\n", __func__, pcr_num); |
| return -1; |
| } |
| if (pcrpid == -1) { |
| pcr_table[pcr_num].turn_on = 0; |
| pcr_table[pcr_num].stream_id = -1; |
| pcr_table[pcr_num].pcr_pid = -1; |
| tsout_config_pcr_table(pcr_num, -1, sid); |
| } else { |
| pcr_table[pcr_num].turn_on = 1; |
| pcr_table[pcr_num].stream_id = sid; |
| pcr_table[pcr_num].pcr_pid = pcrpid; |
| tsout_config_pcr_table(pcr_num, pcrpid, sid); |
| } |
| return 0; |
| } |
| |
| /** |
| * get pcr value |
| * \param pcr_num |
| * \param pcr:pcr value |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_get_pcr(int pcr_num, uint64_t *pcr) |
| { |
| if (pcr_num >= MAX_PCR_NUM) { |
| dprint("%s num:%d invalid\n", __func__, pcr_num); |
| return -1; |
| } |
| if (!pcr_table[pcr_num].turn_on) { |
| dprint("%s num:%d close\n", __func__, pcr_num); |
| return -1; |
| } |
| tsout_config_get_pcr(pcr_num, pcr); |
| return 0; |
| } |
| |
| struct out_elem *ts_output_find_same_section_pid(int sid, int pid) |
| { |
| int i = 0; |
| |
| for (i = 0; i < MAX_OUT_ELEM_NUM; i++) { |
| struct out_elem *pout = &out_elem_table[i]; |
| |
| if (pout->used && |
| pout->sid == sid && |
| pout->format == SECTION_FORMAT && |
| pout->es_pes->pid == pid) { |
| return pout; |
| } |
| } |
| return NULL; |
| } |
| |
| struct out_elem *ts_output_find_dvr(int sid) |
| { |
| int i = 0; |
| |
| for (i = 0; i < MAX_OUT_ELEM_NUM; i++) { |
| struct out_elem *pout = &out_elem_table[i]; |
| |
| if (pout->used && |
| pout->sid == sid && pout->format == DVR_FORMAT) { |
| return pout; |
| } |
| } |
| return NULL; |
| } |
| |
| /** |
| * open one output pipeline |
| * \param dmx_id:demux id. |
| * \param sid:stream id. |
| * \param format:output format. |
| * \param type:input content type. |
| * \param media_type:aucpu support format |
| * \param output_mode:1 will output raw mode,just for ES. |
| * \retval return out_elem. |
| * \retval NULL:fail. |
| */ |
| struct out_elem *ts_output_open(int sid, u8 dmx_id, u8 format, |
| enum content_type type, int media_type, |
| int output_mode) |
| { |
| struct bufferid_attr attr; |
| int ret = 0; |
| struct out_elem *pout; |
| struct ts_out *ts_out_tmp = NULL; |
| |
| pr_dbg("%s sid:%d, format:%d, type:%d ", __func__, sid, format, type); |
| pr_dbg("media_type:%d, output_mode:%d\n", media_type, output_mode); |
| |
| if (sid >= MAX_SID_NUM) { |
| dprint("%s sid:%d fail\n", __func__, sid); |
| return NULL; |
| } |
| pout = _find_free_elem(); |
| if (!pout) { |
| dprint("%s find free elem sid:%d fail\n", __func__, sid); |
| return NULL; |
| } |
| pout->dmx_id = dmx_id; |
| pout->format = format; |
| pout->sid = sid; |
| pout->pid_list = NULL; |
| pout->output_mode = output_mode; |
| pout->type = type; |
| pout->media_type = media_type; |
| pout->ref = 0; |
| pout->newest_pts = 0; |
| |
| memset(&attr, 0, sizeof(struct bufferid_attr)); |
| attr.mode = OUTPUT_MODE; |
| |
| if (format == ES_FORMAT) { |
| attr.is_es = 1; |
| ret = SC2_bufferid_alloc(&attr, &pout->pchan, &pout->pchan1); |
| if (ret != 0) { |
| dprint("%s sid:%d SC2_bufferid_alloc fail\n", |
| __func__, sid); |
| return NULL; |
| } |
| pout->enable = 0; |
| pout->remain_len = 0; |
| pout->cache_len = 0; |
| pout->cache = NULL; |
| pout->aucpu_handle = -1; |
| pout->aucpu_start = 0; |
| pout->aucpu_pts_handle = -1; |
| pout->aucpu_pts_start = 0; |
| } else { |
| if (format == DVR_FORMAT && dump_dvr_ts) |
| dump_file_open(DVR_DUMP_FILE, &dvr_dump_file, 0, 0, 1); |
| |
| ret = SC2_bufferid_alloc(&attr, &pout->pchan, NULL); |
| if (ret != 0) { |
| dprint("%s sid:%d SC2_bufferid_alloc fail\n", |
| __func__, sid); |
| return NULL; |
| } |
| pout->aucpu_handle = -1; |
| pout->aucpu_start = 0; |
| pout->aucpu_pts_handle = -1; |
| pout->aucpu_pts_start = 0; |
| pout->enable = 0; |
| pout->remain_len = 0; |
| pout->cache_len = READ_CACHE_SIZE; |
| pout->cache = kmalloc(pout->cache_len, GFP_KERNEL); |
| if (!pout->cache) { |
| SC2_bufferid_dealloc(pout->pchan); |
| dprint("%s sid:%d kmalloc cache fail\n", __func__, sid); |
| return NULL; |
| } |
| } |
| |
| ts_out_tmp = kmalloc(sizeof(*ts_out_tmp), GFP_KERNEL); |
| if (!ts_out_tmp) { |
| dprint("ts out list fail\n"); |
| SC2_bufferid_dealloc(pout->pchan); |
| kfree(pout->cache); |
| return NULL; |
| } |
| |
| if (format == ES_FORMAT) { |
| ts_out_tmp->es_params = |
| kmalloc(sizeof(struct es_params_t), GFP_KERNEL); |
| if (!ts_out_tmp->es_params) { |
| dprint("ts out es_params fail\n"); |
| SC2_bufferid_dealloc(pout->pchan); |
| kfree(pout->cache); |
| kfree(ts_out_tmp); |
| return NULL; |
| } |
| memset(ts_out_tmp->es_params, 0, |
| sizeof(struct es_params_t)); |
| ts_out_tmp->es_params->last_header[0] = 0xff; |
| ts_out_tmp->es_params->last_header[1] = 0xff; |
| } else { |
| ts_out_tmp->es_params = NULL; |
| } |
| ts_out_tmp->pout = pout; |
| ts_out_tmp->pnext = NULL; |
| |
| if (format == ES_FORMAT) { |
| mutex_lock(&es_output_mutex); |
| add_ts_out_list(&es_out_task_tmp, ts_out_tmp); |
| mutex_unlock(&es_output_mutex); |
| } else { |
| add_ts_out_list(&ts_out_task_tmp, ts_out_tmp); |
| } |
| pout->running = TASK_RUNNING; |
| pout->used = 1; |
| pr_dbg("%s exit\n", __func__); |
| |
| return pout; |
| } |
| |
| /** |
| * close openned index |
| * \param pout |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_close(struct out_elem *pout) |
| { |
| if (pout->ref) |
| return -1; |
| |
| pout->running = TASK_DEAD; |
| |
| if (pout->format == ES_FORMAT) { |
| if (pout->dump_file.file_fp) |
| dump_file_close(&pout->dump_file); |
| |
| mutex_lock(&es_output_mutex); |
| remove_ts_out_list(pout, &es_out_task_tmp); |
| mutex_unlock(&es_output_mutex); |
| } else { |
| if (pout->format == DVR_FORMAT && |
| dvr_dump_file.file_fp) |
| dump_file_close(&dvr_dump_file); |
| remove_ts_out_list(pout, &ts_out_task_tmp); |
| } |
| |
| if (pout->aucpu_handle >= 0) { |
| s32 ret; |
| |
| if (pout->aucpu_start) { |
| ret = aml_aucpu_strm_stop(pout->aucpu_handle); |
| if (ret >= 0) |
| pr_dbg("aml_aucpu_strm_stop success\n"); |
| else |
| pr_dbg("aucpu_stop fail ret:%d\n", ret); |
| pout->aucpu_start = 0; |
| } |
| ret = aml_aucpu_strm_remove(pout->aucpu_handle); |
| if (ret >= 0) |
| pr_dbg("aucpu_strm_remove success\n"); |
| else |
| pr_dbg("aucpu_strm_remove fail ret:%d\n", ret); |
| pout->aucpu_handle = -1; |
| |
| _free_buff(pout->aucpu_mem_phy, |
| pout->aucpu_mem_size, 0, 0); |
| pout->aucpu_mem = 0; |
| } |
| |
| if (pout->aucpu_pts_handle >= 0) { |
| s32 ret; |
| |
| if (pout->aucpu_pts_start) { |
| ret = aml_aucpu_strm_stop(pout->aucpu_pts_handle); |
| if (ret >= 0) |
| pr_dbg("aml_aucpu_strm_stop pts success\n"); |
| else |
| pr_dbg("aucpu_stop fail ret:%d\n", ret); |
| pout->aucpu_pts_start = 0; |
| } |
| ret = aml_aucpu_strm_remove(pout->aucpu_pts_handle); |
| if (ret >= 0) |
| pr_dbg("aucpu_strm_remove pts success\n"); |
| else |
| pr_dbg("aucpu_strm_remove pts fail ret:%d\n", ret); |
| pout->aucpu_pts_handle = -1; |
| |
| _free_buff(pout->aucpu_pts_mem_phy, |
| pout->aucpu_pts_mem_size, 0, 0); |
| pout->aucpu_pts_mem = 0; |
| } |
| |
| if (pout->pchan) { |
| SC2_bufferid_set_enable(pout->pchan, 0); |
| SC2_bufferid_dealloc(pout->pchan); |
| pout->pchan = NULL; |
| } |
| if (pout->pchan1) { |
| SC2_bufferid_set_enable(pout->pchan1, 0); |
| SC2_bufferid_dealloc(pout->pchan1); |
| pout->pchan1 = NULL; |
| } |
| |
| pout->used = 0; |
| pr_dbg("%s end\n", __func__); |
| return 0; |
| } |
| |
| /** |
| * add pid in stream |
| * \param pout |
| * \param pid: |
| * \param pid_mask:0,matched all bits; 0x1FFF matched any PID |
| * \param dmx_id: dmx_id |
| * \param cb_id:same pid ref |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_add_pid(struct out_elem *pout, int pid, int pid_mask, int dmx_id, |
| int *cb_id) |
| { |
| struct pid_entry *pid_slot = NULL; |
| struct es_entry *es_pes = NULL; |
| |
| if (!pout) |
| return -1; |
| |
| if (cb_id) |
| *cb_id = 0; |
| |
| if (pout->pchan) |
| SC2_bufferid_set_enable(pout->pchan, 1); |
| if (pout->pchan1) |
| SC2_bufferid_set_enable(pout->pchan1, 1); |
| |
| pr_dbg("%s pout:0x%lx pid:%d, pid_mask:%d\n", |
| __func__, (unsigned long)pout, pid, pid_mask); |
| if (pout->format == ES_FORMAT || |
| pout->format == PES_FORMAT || pout->format == SECTION_FORMAT) { |
| es_pes = _malloc_es_entry_slot(); |
| if (!es_pes) { |
| dprint("get es entry slot error\n"); |
| return -1; |
| } |
| es_pes->buff_id = pout->pchan->id; |
| es_pes->pid = pid; |
| es_pes->status = pout->format; |
| es_pes->dmx_id = dmx_id; |
| es_pes->pout = pout; |
| pout->es_pes = es_pes; |
| |
| /*before pid filter enable */ |
| if (pout->pchan->sec_level) |
| create_aucpu_inst(pout); |
| if (pout->type == VIDEO_TYPE) { |
| if (((dump_video_es & 0xFFFF) == pout->es_pes->pid && |
| ((dump_video_es >> 16) & 0xFFFF) == pout->sid) || |
| dump_video_es == 0XFFFFFFFF) |
| dump_file_open(VIDEOES_DUMP_FILE, &pout->dump_file, |
| pout->sid, pout->es_pes->pid, 0); |
| } |
| if (pout->type == AUDIO_TYPE) { |
| if (((dump_audio_es & 0xFFFF) == pout->es_pes->pid && |
| ((dump_audio_es >> 16) & 0xFFFF) == pout->sid) || |
| dump_audio_es == 0xFFFFFFFF) |
| dump_file_open(AUDIOES_DUMP_FILE, &pout->dump_file, |
| pout->sid, pout->es_pes->pid, 0); |
| } |
| tsout_config_es_table(es_pes->buff_id, es_pes->pid, |
| pout->sid, 1, !drop_dup, pout->format); |
| } else { |
| if (cb_id) |
| *cb_id = dmx_id; |
| pid_slot = pout->pid_list; |
| while (pid_slot) { |
| if (pid_slot->pid == pid) { |
| pid_slot->ref++; |
| if (cb_id) |
| *cb_id = dmx_id; |
| if (pout->enable == 0) |
| pr_err("!!!!!pout enable is 0, this is danger error!!!!!!\n"); |
| return 0; |
| } |
| pid_slot = pid_slot->pnext; |
| } |
| |
| pid_slot = _malloc_pid_entry_slot(pout->sid, pid); |
| if (!pid_slot) { |
| pr_dbg("malloc pid entry fail\n"); |
| return -1; |
| } |
| pid_slot->pid = pid; |
| pid_slot->pid_mask = pid_mask; |
| pid_slot->used = 1; |
| pid_slot->dmx_id = dmx_id; |
| pid_slot->ref = 1; |
| pid_slot->pout = pout; |
| |
| pid_slot->pnext = pout->pid_list; |
| pout->pid_list = pid_slot; |
| pr_dbg("sid:%d, pid:0x%0x, mask:0x%0x\n", |
| pout->sid, pid_slot->pid, pid_slot->pid_mask); |
| tsout_config_ts_table(pid_slot->pid, pid_slot->pid_mask, |
| pid_slot->id, pout->pchan->id); |
| } |
| pout->enable = 1; |
| return 0; |
| } |
| |
| /** |
| * remove pid in stream |
| * \param pout |
| * \param pid |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_remove_pid(struct out_elem *pout, int pid) |
| { |
| struct pid_entry *cur_pid; |
| struct pid_entry *prev_pid; |
| |
| pr_dbg("%s pout:0x%lx\n", __func__, (unsigned long)pout); |
| if (pout->format == ES_FORMAT || |
| pout->format == PES_FORMAT || pout->format == SECTION_FORMAT) { |
| if (pout->format != pout->es_pes->status) { |
| pr_err("rm pid error pout fmt:%d es_pes fmt:%d\r\n", |
| pout->format, |
| pout->es_pes->status); |
| return 0; |
| } else if (pout->ref <= 1) { |
| tsout_config_es_table(pout->es_pes->buff_id, -1, |
| pout->sid, 1, !drop_dup, pout->format); |
| _free_es_entry_slot(pout->es_pes); |
| // pout->es_pes = NULL; |
| } else { |
| return 0; |
| } |
| } else if (pout->format == DVR_FORMAT) { |
| cur_pid = pout->pid_list; |
| prev_pid = cur_pid; |
| while (cur_pid) { |
| if (cur_pid->pid == pid) { |
| if (cur_pid->ref > 1) { |
| cur_pid->ref--; |
| return 0; |
| } else if (cur_pid->ref == 1) { |
| if (cur_pid == pout->pid_list) |
| pout->pid_list = cur_pid->pnext; |
| else |
| prev_pid->pnext = |
| cur_pid->pnext; |
| break; |
| } |
| } |
| prev_pid = cur_pid; |
| cur_pid = cur_pid->pnext; |
| } |
| if (cur_pid) { |
| tsout_config_ts_table(-1, cur_pid->pid_mask, |
| cur_pid->id, pout->pchan->id); |
| _free_pid_entry_slot(cur_pid); |
| } |
| if (pout->pid_list) |
| return 0; |
| } |
| pout->enable = 0; |
| pr_dbg("%s line:%d\n", __func__, __LINE__); |
| return 0; |
| } |
| |
| int ts_output_set_mem(struct out_elem *pout, int memsize, |
| int sec_level, int pts_memsize, int pts_level) |
| { |
| int ret = 0; |
| pr_dbg("%s mem size:0x%0x, pts_memsize:0x%0x, sec_level:%d\n", |
| __func__, memsize, pts_memsize, sec_level); |
| |
| if (pout && pout->pchan) { |
| ret = SC2_bufferid_set_mem(pout->pchan, memsize, sec_level); |
| if (ret != 0) |
| return -1; |
| } |
| if (pout && pout->pchan1) { |
| ret = SC2_bufferid_set_mem(pout->pchan1, |
| pts_memsize, pts_level); |
| if (ret != 0) |
| return -1; |
| } |
| return 0; |
| } |
| |
| int ts_output_set_sec_mem(struct out_elem *pout, |
| unsigned int buf, unsigned int size) |
| { |
| pr_dbg("%s size:0x%0x\n", __func__, size); |
| |
| if (pout && pout->pchan) |
| SC2_bufferid_set_sec_mem(pout->pchan, buf, size); |
| return 0; |
| } |
| |
| int ts_output_get_mem_info(struct out_elem *pout, |
| unsigned int *total_size, |
| unsigned int *buf_phy_start, |
| unsigned int *free_size, unsigned int *wp_offset, |
| __u64 *newest_pts) |
| { |
| *total_size = pout->pchan->mem_size; |
| *buf_phy_start = pout->pchan->mem_phy; |
| *wp_offset = SC2_bufferid_get_wp_offset(pout->pchan); |
| *free_size = SC2_bufferid_get_free_size(pout->pchan); |
| if (newest_pts) |
| *newest_pts = pout->newest_pts; |
| return 0; |
| } |
| |
| /** |
| * reset index pipeline, clear the buf |
| * \param pout |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_reset(struct out_elem *pout) |
| { |
| return 0; |
| } |
| |
| /** |
| * set callback for getting data |
| * \param pout |
| * \param cb |
| * \param udata:private data |
| * \param cb_id:cb_id |
| * \param format:format |
| * \param is_sec: is section callback |
| * \param demux_id:dmx id |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_add_cb(struct out_elem *pout, ts_output_cb cb, void *udata, |
| u8 cb_id, u8 format, bool is_sec, u8 demux_id) |
| { |
| struct cb_entry *tmp_cb = NULL; |
| |
| if (format == DVR_FORMAT) { |
| tmp_cb = pout->cb_ts_list; |
| while (tmp_cb) { |
| if (tmp_cb->id == cb_id && |
| tmp_cb->format == DVR_FORMAT) { |
| tmp_cb->ref++; |
| if (tmp_cb->ref < MAX_FEED_NUM) |
| tmp_cb->udata[tmp_cb->ref] = udata; |
| return 0; |
| } |
| tmp_cb = tmp_cb->next; |
| } |
| } |
| |
| tmp_cb = vmalloc(sizeof(*tmp_cb)); |
| if (!tmp_cb) { |
| dprint("%s malloc fail\n", __func__); |
| return -1; |
| } |
| tmp_cb->cb = cb; |
| tmp_cb->udata[0] = udata; |
| tmp_cb->next = NULL; |
| tmp_cb->format = format; |
| tmp_cb->ref = 0; |
| tmp_cb->id = cb_id; |
| tmp_cb->demux_id = demux_id; |
| |
| if (is_sec) { |
| tmp_cb->next = pout->cb_sec_list; |
| pout->cb_sec_list = tmp_cb; |
| } else { |
| if (pout->type == VIDEO_TYPE || pout->type == AUDIO_TYPE) |
| mutex_lock(&es_output_mutex); |
| |
| tmp_cb->next = pout->cb_ts_list; |
| pout->cb_ts_list = tmp_cb; |
| |
| if (pout->type == VIDEO_TYPE || pout->type == AUDIO_TYPE) |
| mutex_unlock(&es_output_mutex); |
| } |
| |
| pout->ref++; |
| |
| if (pout->type == VIDEO_TYPE || pout->type == AUDIO_TYPE) |
| mod_timer(&es_out_task_tmp.out_timer, |
| jiffies + msecs_to_jiffies(out_es_flush_time)); |
| else |
| mod_timer(&ts_out_task_tmp.out_timer, |
| jiffies + msecs_to_jiffies(out_flush_time)); |
| return 0; |
| } |
| |
| static void remove_udata(struct cb_entry *tmp_cb, void *udata) |
| { |
| int i, j; |
| |
| /*remove the free feed*/ |
| for (i = 0; i <= tmp_cb->ref && i < MAX_FEED_NUM; i++) { |
| if (tmp_cb->udata[i] == udata) { |
| for (j = i; j < tmp_cb->ref && j < MAX_FEED_NUM - 1; |
| j++) |
| tmp_cb->udata[j] = tmp_cb->udata[j + 1]; |
| } |
| } |
| } |
| |
| /** |
| * remove callback for getting data |
| * \param pout |
| * \param cb |
| * \param udata:private data |
| * \param cb_id:dmx_id |
| * \param is_sec: is section callback |
| * \retval 0:success. |
| * \retval -1:fail. |
| */ |
| int ts_output_remove_cb(struct out_elem *pout, ts_output_cb cb, void *udata, |
| u8 cb_id, bool is_sec) |
| { |
| struct cb_entry *tmp_cb = NULL; |
| struct cb_entry *pre_cb = NULL; |
| |
| if (pout->format == DVR_FORMAT) { |
| tmp_cb = pout->cb_ts_list; |
| while (tmp_cb) { |
| if (tmp_cb->id == cb_id && |
| tmp_cb->format == DVR_FORMAT) { |
| if (tmp_cb->ref == 0) { |
| if (tmp_cb == pout->cb_ts_list) |
| pout->cb_ts_list = tmp_cb->next; |
| else |
| pre_cb->next = tmp_cb->next; |
| vfree(tmp_cb); |
| pout->ref--; |
| return 0; |
| } |
| remove_udata(tmp_cb, udata); |
| tmp_cb->ref--; |
| return 0; |
| } |
| pre_cb = tmp_cb; |
| tmp_cb = tmp_cb->next; |
| } |
| return 0; |
| } |
| if (is_sec) { |
| tmp_cb = pout->cb_sec_list; |
| while (tmp_cb) { |
| if (tmp_cb->cb == cb && tmp_cb->udata[0] == udata) { |
| if (tmp_cb == pout->cb_sec_list) |
| pout->cb_sec_list = tmp_cb->next; |
| else |
| pre_cb->next = tmp_cb->next; |
| |
| vfree(tmp_cb); |
| pout->ref--; |
| return 0; |
| } |
| pre_cb = tmp_cb; |
| tmp_cb = tmp_cb->next; |
| } |
| if (!pout->cb_sec_list) |
| pout->remain_len = 0; |
| } else { |
| if (pout->type == VIDEO_TYPE || pout->type == AUDIO_TYPE) |
| mutex_lock(&es_output_mutex); |
| |
| tmp_cb = pout->cb_ts_list; |
| while (tmp_cb) { |
| if (tmp_cb->cb == cb && tmp_cb->udata[0] == udata) { |
| if (tmp_cb == pout->cb_ts_list) |
| pout->cb_ts_list = tmp_cb->next; |
| else |
| pre_cb->next = tmp_cb->next; |
| |
| vfree(tmp_cb); |
| pout->ref--; |
| if (pout->type == VIDEO_TYPE || |
| pout->type == AUDIO_TYPE) |
| mutex_unlock(&es_output_mutex); |
| return 0; |
| } |
| pre_cb = tmp_cb; |
| tmp_cb = tmp_cb->next; |
| } |
| if (pout->type == VIDEO_TYPE || pout->type == AUDIO_TYPE) |
| mutex_unlock(&es_output_mutex); |
| } |
| return 0; |
| } |
| |
| int ts_output_dump_info(char *buf) |
| { |
| int i = 0; |
| int count = 0; |
| int r, total = 0; |
| |
| r = sprintf(buf, "********dvr********\n"); |
| buf += r; |
| total += r; |
| |
| for (i = 0; i < MAX_OUT_ELEM_NUM; i++) { |
| struct out_elem *pout = &out_elem_table[i]; |
| unsigned int total_size = 0; |
| unsigned int buf_phy_start = 0; |
| unsigned int free_size = 0; |
| unsigned int wp_offset = 0; |
| struct pid_entry *pid_list; |
| struct cb_entry *tmp_cb = NULL; |
| |
| if (pout->used && pout->format == DVR_FORMAT) { |
| tmp_cb = pout->cb_ts_list; |
| |
| r = sprintf(buf, "%d sid:0x%0x ref:%d ", |
| count, pout->sid, pout->ref); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, "dmx_id "); |
| buf += r; |
| total += r; |
| |
| while (tmp_cb) { |
| r = sprintf(buf, "%d ", tmp_cb->demux_id); |
| buf += r; |
| total += r; |
| |
| tmp_cb = tmp_cb->next; |
| } |
| |
| ts_output_get_mem_info(pout, |
| &total_size, |
| &buf_phy_start, |
| &free_size, &wp_offset, NULL); |
| r = sprintf(buf, |
| "mem total:0x%0x, buf_base:0x%0x, ", |
| total_size, buf_phy_start); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, |
| "free size:0x%0x, rp:0x%0x, wp:0x%0x\n", |
| free_size, pout->pchan->r_offset, |
| wp_offset); |
| buf += r; |
| total += r; |
| |
| pid_list = pout->pid_list; |
| r = sprintf(buf, " pid:"); |
| buf += r; |
| total += r; |
| |
| while (pid_list) { |
| r = sprintf(buf, "0x%0x ", pid_list->pid); |
| buf += r; |
| total += r; |
| pid_list = pid_list->pnext; |
| } |
| r = sprintf(buf, "\n"); |
| buf += r; |
| total += r; |
| |
| count++; |
| } |
| } |
| |
| r = sprintf(buf, "********PES********\n"); |
| buf += r; |
| total += r; |
| |
| count = 0; |
| for (i = 0; i < MAX_ES_NUM; i++) { |
| struct es_entry *es_slot = &es_table[i]; |
| unsigned int total_size = 0; |
| unsigned int buf_phy_start = 0; |
| unsigned int free_size = 0; |
| unsigned int wp_offset = 0; |
| |
| if (es_slot->used && es_slot->status == PES_FORMAT) { |
| r = sprintf(buf, "%d dmx_id:%d sid:0x%0x type:%d,", |
| count, es_slot->dmx_id, |
| es_slot->pout->sid, es_slot->pout->type); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, "pid:0x%0x ", es_slot->pid); |
| buf += r; |
| total += r; |
| |
| ts_output_get_mem_info(es_slot->pout, |
| &total_size, |
| &buf_phy_start, |
| &free_size, &wp_offset, NULL); |
| r = sprintf(buf, |
| "mem total:0x%0x, buf_base:0x%0x, ", |
| total_size, buf_phy_start); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, |
| "free size:0x%0x, rp:0x%0x, wp:0x%0x\n", |
| free_size, es_slot->pout->pchan->r_offset, |
| wp_offset); |
| buf += r; |
| total += r; |
| |
| count++; |
| } |
| } |
| |
| r = sprintf(buf, "********ES********\n"); |
| buf += r; |
| total += r; |
| count = 0; |
| |
| for (i = 0; i < MAX_ES_NUM; i++) { |
| struct es_entry *es_slot = &es_table[i]; |
| unsigned int total_size = 0; |
| unsigned int buf_phy_start = 0; |
| unsigned int free_size = 0; |
| unsigned int wp_offset = 0; |
| |
| if (es_slot->used && es_slot->status == ES_FORMAT) { |
| r = sprintf(buf, "%d dmx_id:%d sid:0x%0x type:%s", |
| count, es_slot->dmx_id, es_slot->pout->sid, |
| (es_slot->pout->type == AUDIO_TYPE) ? |
| "aud" : "vid"); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, " pid:0x%0x ", es_slot->pid); |
| buf += r; |
| total += r; |
| |
| ts_output_get_mem_info(es_slot->pout, |
| &total_size, |
| &buf_phy_start, |
| &free_size, &wp_offset, NULL); |
| |
| r = sprintf(buf, |
| "mem total:0x%0x, buf_base:0x%0x, ", |
| total_size, buf_phy_start); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, |
| "free size:0x%0x, rp:0x%0x, wp:0x%0x, ", |
| free_size, es_slot->pout->pchan->r_offset, |
| wp_offset); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, |
| "h rp:0x%0x, h wp:0x%0x, ", |
| es_slot->pout->pchan1->r_offset, |
| SC2_bufferid_get_wp_offset( |
| es_slot->pout->pchan1)); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, |
| "sec_level:0x%0x\n", |
| es_slot->pout->pchan->sec_level); |
| buf += r; |
| total += r; |
| |
| count++; |
| } |
| } |
| r = sprintf(buf, "********section********\n"); |
| buf += r; |
| total += r; |
| count = 0; |
| |
| for (i = 0; i < MAX_ES_NUM; i++) { |
| struct es_entry *es_slot = &es_table[i]; |
| unsigned int total_size = 0; |
| unsigned int buf_phy_start = 0; |
| unsigned int free_size = 0; |
| unsigned int wp_offset = 0; |
| struct cb_entry *tmp_cb = NULL; |
| struct out_elem *pout = NULL; |
| |
| if (es_slot->used && es_slot->status == SECTION_FORMAT) { |
| pout = es_slot->pout; |
| tmp_cb = pout->cb_sec_list; |
| |
| r = sprintf(buf, "%d dmx_id:", count); |
| buf += r; |
| total += r; |
| |
| while (tmp_cb) { |
| r = sprintf(buf, "%d ", tmp_cb->demux_id); |
| buf += r; |
| total += r; |
| |
| tmp_cb = tmp_cb->next; |
| } |
| |
| r = sprintf(buf, "sid:0x%0x ", es_slot->pout->sid); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, "pid:0x%0x ref:%d ", |
| es_slot->pid, es_slot->pout->ref); |
| buf += r; |
| total += r; |
| |
| ts_output_get_mem_info(es_slot->pout, |
| &total_size, |
| &buf_phy_start, |
| &free_size, &wp_offset, NULL); |
| |
| r = sprintf(buf, |
| "mem total:0x%0x, buf_base:0x%0x, ", |
| total_size, buf_phy_start); |
| buf += r; |
| total += r; |
| |
| r = sprintf(buf, |
| "free size:0x%0x, wp:0x%0x\n", |
| free_size, wp_offset); |
| buf += r; |
| total += r; |
| |
| count++; |
| } |
| } |
| |
| return total; |
| } |
| |
| static void update_dvr_sid(struct out_elem *pout, int sid, int dmx_no) |
| { |
| struct pid_entry *head_pid_slot = NULL; |
| struct pid_entry *prev_pid_slot = NULL; |
| struct pid_entry *new_pid_slot = NULL; |
| struct pid_entry *pid_slot = NULL; |
| |
| pout->sid = sid; |
| pid_slot = pout->pid_list; |
| while (pid_slot) { |
| dprint("change dmx id:%d, dvr dmx filter sid:0x%0x, pid:0x%0x\n", |
| dmx_no, pout->sid, pid_slot->pid); |
| /*free slot*/ |
| tsout_config_ts_table(-1, pid_slot->pid_mask, |
| pid_slot->id, pout->pchan->id); |
| |
| /*remalloc slot and */ |
| new_pid_slot = _malloc_pid_entry_slot(pout->sid, pid_slot->pid); |
| if (!new_pid_slot) { |
| pr_dbg("malloc pid entry fail\n"); |
| _free_pid_entry_slot(pid_slot); |
| pid_slot = pid_slot->pnext; |
| return; |
| } |
| new_pid_slot->pid = pid_slot->pid; |
| new_pid_slot->pid_mask = pid_slot->pid_mask; |
| new_pid_slot->used = 1; |
| new_pid_slot->dmx_id = pid_slot->dmx_id; |
| new_pid_slot->ref = pid_slot->ref; |
| new_pid_slot->pout = pout; |
| |
| if (!head_pid_slot) |
| head_pid_slot = new_pid_slot; |
| else |
| prev_pid_slot->pnext = new_pid_slot; |
| |
| prev_pid_slot = new_pid_slot; |
| tsout_config_ts_table(new_pid_slot->pid, |
| new_pid_slot->pid_mask, |
| new_pid_slot->id, |
| pout->pchan->id); |
| |
| _free_pid_entry_slot(pid_slot); |
| pid_slot = pid_slot->pnext; |
| } |
| pout->pid_list = head_pid_slot; |
| } |
| |
| int ts_output_update_filter(int dmx_no, int sid) |
| { |
| int i = 0; |
| |
| /*update dvr filter*/ |
| for (i = 0; i < MAX_OUT_ELEM_NUM; i++) { |
| struct out_elem *pout = &out_elem_table[i]; |
| u8 flag = 0; |
| |
| if (pout->used && pout->format == DVR_FORMAT) { |
| struct cb_entry *tmp_cb = pout->cb_ts_list; |
| |
| while (tmp_cb) { |
| if (tmp_cb->demux_id == dmx_no) { |
| flag = 1; |
| break; |
| } |
| tmp_cb = tmp_cb->next; |
| } |
| if (flag) |
| update_dvr_sid(pout, sid, dmx_no); |
| } |
| } |
| /*update es table filter*/ |
| for (i = 0; i < MAX_ES_NUM; i++) { |
| struct es_entry *es_slot = &es_table[i]; |
| struct out_elem *pout = NULL; |
| u8 flag = 0; |
| |
| if (es_slot->used) { |
| struct cb_entry *tmp_cb = NULL; |
| pout = es_slot->pout; |
| |
| if (es_slot->status == ES_FORMAT || es_slot->status == PES_FORMAT) |
| tmp_cb = pout->cb_ts_list; |
| else if (es_slot->status == SECTION_FORMAT) |
| tmp_cb = pout->cb_sec_list; |
| |
| while (tmp_cb) { |
| if (tmp_cb->demux_id == dmx_no) { |
| flag = 1; |
| break; |
| } |
| tmp_cb = tmp_cb->next; |
| } |
| |
| if (flag) { |
| pout->sid = sid; |
| dprint("change dmx id:%d, filter sid:0x%0x, pid:0x%0x\n", |
| dmx_no, pout->sid, es_slot->pid); |
| tsout_config_es_table(es_slot->buff_id, es_slot->pid, |
| pout->sid, 1, !drop_dup, pout->format); |
| } |
| } |
| } |
| return 0; |
| } |
| |