📄 av7110_av.c
字号:
/* * av7110_av.c: audio and video MPEG decoder stuff * * Copyright (C) 1999-2002 Ralph Metzler * & Marcus Metzler for convergence integrated media GmbH * * originally based on code by: * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> * * 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. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * * the project's page is at http://www.linuxtv.org/dvb/ */#include <linux/types.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/byteorder/swabb.h>#include <linux/smp_lock.h>#include <linux/fs.h>#define DEBUG_VARIABLE av7110_debugextern int av7110_debug;#include "av7110.h"#include "av7110_hw.h"#include "av7110_av.h"#include "av7110_ipack.h"#include "dvb_functions.h"/* MPEG-2 (ISO 13818 / H.222.0) stream types */#define PROG_STREAM_MAP 0xBC#define PRIVATE_STREAM1 0xBD#define PADDING_STREAM 0xBE#define PRIVATE_STREAM2 0xBF#define AUDIO_STREAM_S 0xC0#define AUDIO_STREAM_E 0xDF#define VIDEO_STREAM_S 0xE0#define VIDEO_STREAM_E 0xEF#define ECM_STREAM 0xF0#define EMM_STREAM 0xF1#define DSM_CC_STREAM 0xF2#define ISO13522_STREAM 0xF3#define PROG_STREAM_DIR 0xFF#define PTS_DTS_FLAGS 0xC0//pts_dts flags#define PTS_ONLY 0x80#define PTS_DTS 0xC0#define TS_SIZE 188#define TRANS_ERROR 0x80#define PAY_START 0x40#define TRANS_PRIO 0x20#define PID_MASK_HI 0x1F//flags#define TRANS_SCRMBL1 0x80#define TRANS_SCRMBL2 0x40#define ADAPT_FIELD 0x20#define PAYLOAD 0x10#define COUNT_MASK 0x0F// adaptation flags#define DISCON_IND 0x80#define RAND_ACC_IND 0x40#define ES_PRI_IND 0x20#define PCR_FLAG 0x10#define OPCR_FLAG 0x08#define SPLICE_FLAG 0x04#define TRANS_PRIV 0x02#define ADAP_EXT_FLAG 0x01// adaptation extension flags#define LTW_FLAG 0x80#define PIECE_RATE 0x40#define SEAM_SPLICE 0x20static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, struct dvb_demux_feed *feed);int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len){ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv;// DEB_EE(("struct dvb_filter_pes2ts:%p\n", p2t)); if (!(dvbdmxfeed->ts_type & TS_PACKET)) return 0; if (buf[3] == 0xe0) // video PES do not have a length in TS buf[4] = buf[5] = 0; if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) return dvbdmxfeed->cb.ts(buf, len, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); else return dvb_filter_pes2ts(p2t, buf, len, 1);}static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data){ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;// DEB_EE(("dvb_demux_feed:%p\n", dvbdmxfeed)); dvbdmxfeed->cb.ts(data, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); return 0;}int av7110_av_start_record(struct av7110 *av7110, int av, struct dvb_demux_feed *dvbdmxfeed){ struct dvb_demux *dvbdmx = dvbdmxfeed->demux; DEB_EE(("av7110: %p, dvb_demux_feed:%p\n", av7110, dvbdmxfeed)); if (av7110->playing || (av7110->rec_mode & av)) return -EBUSY; av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); dvbdmx->recording = 1; av7110->rec_mode |= av; switch (av7110->rec_mode) { case RP_AUDIO: dvb_filter_pes2ts_init(&av7110->p2t[0], dvbdmx->pesfilter[0]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[0]); av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); break; case RP_VIDEO: dvb_filter_pes2ts_init(&av7110->p2t[1], dvbdmx->pesfilter[1]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[1]); av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); break; case RP_AV: dvb_filter_pes2ts_init(&av7110->p2t[0], dvbdmx->pesfilter[0]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[0]); dvb_filter_pes2ts_init(&av7110->p2t[1], dvbdmx->pesfilter[1]->pid, dvb_filter_pes2ts_cb, (void *) dvbdmx->pesfilter[1]); av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); break; } return 0;}int av7110_av_start_play(struct av7110 *av7110, int av){ DEB_EE(("av7110: %p\n", av7110)); if (av7110->rec_mode) return -EBUSY; if (av7110->playing & av) return -EBUSY; av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); if (av7110->playing == RP_NONE) { av7110_ipack_reset(&av7110->ipack[0]); av7110_ipack_reset(&av7110->ipack[1]); } av7110->playing |= av; switch (av7110->playing) { case RP_AUDIO: av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); break; case RP_VIDEO: av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); av7110->sinfo = 0; break; case RP_AV: av7110->sinfo = 0; av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); break; } return av7110->playing;}void av7110_av_stop(struct av7110 *av7110, int av){ DEB_EE(("av7110: %p\n", av7110)); if (!(av7110->playing & av) && !(av7110->rec_mode & av)) return; av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); if (av7110->playing) { av7110->playing &= ~av; switch (av7110->playing) { case RP_AUDIO: av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); break; case RP_VIDEO: av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); break; case RP_NONE: av7110_set_vidmode(av7110, av7110->vidmode); break; } } else { av7110->rec_mode &= ~av; switch (av7110->rec_mode) { case RP_AUDIO: av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); break; case RP_VIDEO: av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); break; case RP_NONE: break; } }}int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen){ int len; u32 sync; u16 blen; DEB_EE(("dvb_ring_buffer_t: %p\n", buf)); if (!dlen) { wake_up(&buf->queue); return -1; } while (1) { if ((len = dvb_ringbuffer_avail(buf)) < 6) return -1; sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24; sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16; sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8; sync |= DVB_RINGBUFFER_PEEK(buf, 3); if (((sync &~ 0x0f) == 0x000001e0) || ((sync &~ 0x1f) == 0x000001c0) || (sync == 0x000001bd)) break; printk("resync\n"); DVB_RINGBUFFER_SKIP(buf, 1); } blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8; blen |= DVB_RINGBUFFER_PEEK(buf, 5); blen += 6; if (len < blen || blen > dlen) { //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen); wake_up(&buf->queue); return -1; } dvb_ringbuffer_read(buf, dest, (size_t) blen, 0); DEB_S(("pread=0x%08lx, pwrite=0x%08lx\n", (unsigned long) buf->pread, (unsigned long) buf->pwrite)); wake_up(&buf->queue); return blen;}int av7110_set_volume(struct av7110 *av7110, int volleft, int volright){ int err, vol, val, balance = 0; DEB_EE(("av7110: %p\n", av7110)); switch (av7110->adac_type) { case DVB_ADAC_TI: volleft = (volleft * 256) / 1036; volright = (volright * 256) / 1036; if (volleft > 0x3f) volleft = 0x3f; if (volright > 0x3f) volright = 0x3f; if ((err = SendDAC(av7110, 3, 0x80 + volleft))) return err; return SendDAC(av7110, 4, volright); case DVB_ADAC_CRYSTAL: volleft = 127 - volleft / 2; volright = 127 - volright / 2; i2c_writereg(av7110, 0x20, 0x03, volleft); i2c_writereg(av7110, 0x20, 0x04, volright); return 0; case DVB_ADAC_MSP: vol = (volleft > volright) ? volleft : volright; val = (vol * 0x73 / 255) << 8; if (vol > 0) balance = ((volright - volleft) * 127) / vol; msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ return 0; } return 0;}void av7110_set_vidmode(struct av7110 *av7110, int mode){ DEB_EE(("av7110: %p\n", av7110)); av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); if (!av7110->playing) { ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], av7110->pids[DMX_PES_AUDIO], av7110->pids[DMX_PES_TELETEXT], 0, av7110->pids[DMX_PES_PCR]); av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); }}static int sw2mode[16] = { VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,};static void get_video_format(struct av7110 *av7110, u8 *buf, int count){ int i; int hsize, vsize; int sw; u8 *p; DEB_EE(("av7110: %p\n", av7110)); if (av7110->sinfo) return; for (i = 7; i < count - 10; i++) { p = buf + i; if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) continue; p += 4; hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); vsize = ((p[1] &0x0F) << 8) | (p[2]); sw = (p[3] & 0x0F); av7110_set_vidmode(av7110, sw2mode[sw]); DEB_S(("dvb: playback %dx%d fr=%d\n", hsize, vsize, sw)); av7110->sinfo = 1; break; }}/**************************************************************************** * I/O buffer management and control ****************************************************************************/static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, const char *buf, unsigned long count){ unsigned long todo = count; int free; while (todo > 0) { if (dvb_ringbuffer_free(rbuf) < 2048) { if (wait_event_interruptible(rbuf->queue, (dvb_ringbuffer_free(rbuf) >= 2048))) return count - todo; } free = dvb_ringbuffer_free(rbuf); if (free > todo) free = todo; dvb_ringbuffer_write(rbuf, buf, free, 0); todo -= free; buf += free; } return count - todo;}static void play_video_cb(u8 *buf, int count, void *priv){ struct av7110 *av7110 = (struct av7110 *) priv; DEB_EE(("av7110: %p\n", av7110)); if ((buf[3] & 0xe0) == 0xe0) { get_video_format(av7110, buf, count); aux_ring_buffer_write(&av7110->avout, buf, count); } else aux_ring_buffer_write(&av7110->aout, buf, count);}static void play_audio_cb(u8 *buf, int count, void *priv){ struct av7110 *av7110 = (struct av7110 *) priv; DEB_EE(("av7110: %p\n", av7110)); aux_ring_buffer_write(&av7110->aout, buf, count);}#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)static ssize_t dvb_play(struct av7110 *av7110, const u8 *buf, unsigned long count, int nonblock, int type, int umem){ unsigned long todo = count, n; DEB_EE(("av7110: %p\n", av7110)); if (!av7110->kbuf[type]) return -ENOBUFS; if (nonblock && !FREE_COND) return -EWOULDBLOCK; while (todo > 0) { if (!FREE_COND) { if (nonblock) return count - todo; if (wait_event_interruptible(av7110->avout.queue, FREE_COND)) return count - todo; } n = todo; if (n > IPACKS * 2) n = IPACKS * 2; if (umem) { if (copy_from_user(av7110->kbuf[type], buf, n)) return -EFAULT; av7110_ipack_instant_repack(av7110->kbuf[type], n, &av7110->ipack[type]); } else { av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); } todo -= n; buf += n; } return count - todo;}static ssize_t dvb_aplay(struct av7110 *av7110, const u8 *buf, unsigned long count, int nonblock, int type){ unsigned long todo = count, n; DEB_EE(("av7110: %p\n", av7110)); if (!av7110->kbuf[type]) return -ENOBUFS; if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) return -EWOULDBLOCK; while (todo > 0) { if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) { if (nonblock) return count - todo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -