📄 spu_mixer.c
字号:
/* Ogle - A video player * Copyright (C) 2000, 2001 Bj鰎n Englund, H錵an Hjort * * 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 */#include <inttypes.h>#include <stdio.h>#include <assert.h>#include <stdlib.h>#include <signal.h>#include <sys/mman.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/shm.h>#include <fcntl.h>#include <unistd.h>#include <sys/msg.h>#include <errno.h>#include <string.h>#include "debug_print.h"#include "common.h"#include "queue.h"#include "timemath.h"#include "sync.h"#include "spu_mixer.h"#ifndef SHM_SHARE_MMU#define SHM_SHARE_MMU 0#endif#ifdef DEBUG#define GETBYTES(a,b) getbytes(a,b)#else#define GETBYTES(a,b) getbytes(a)#endiftypedef struct { int spu_size; uint16_t DCSQT_offset; int next_DCSQ_offset; int last_DCSQ; uint16_t fieldoffset[2]; unsigned char *buffer; unsigned char *next_buffer; int scr_nr; uint64_t base_time; uint64_t next_time; int start_time; int width; int height; int x_start; int x_end; int y_start; int y_end; int display_start; int has_highlight; uint8_t color[4]; uint8_t contrast[4];} spu_handle_t;typedef struct { uint8_t color[4]; uint8_t contrast[4]; int x_start; int y_start; int x_end; int y_end;} highlight_t;extern ctrl_data_t *ctrl_data;extern ctrl_time_t *ctrl_time;static int stream_shmid;static char *stream_shmaddr;static int data_buf_shmid;static char *data_buf_shmaddr;static int aligned;static uint16_t fieldoffset[2];static uint16_t field = 0;static spu_handle_t spu_info = { 0 };static int initialized = 0;static uint32_t palette_yuv[16];static uint32_t palette_rgb[16];static uint32_t *palette;static void (*mix_function)(uint32_t color, uint32_t contrast, unsigned int len, uint8_t* pixel, int, uint8_t*, uint8_t*) = NULL;static highlight_t highlight = {{0,1,2,3}, {0xf, 0xa, 0x6,0x2}, 2,2,718, 450};extern int video_scr_nr;extern int msgqid;extern MsgEventQ_t *msgq;static int flush_to_scrid = -1;static int rgbmode,pixelstride;#define MAX_BUF_SIZE 65536#define MODE_RGB 0x1#define MODE_BGR 0x2#define MODE_RGB_ALIEN 0x5#define MODE_BGR_ALIEN 0x6#define MODE_ALIEN_MASK 0x4extern void redraw_request(void);extern int register_event_handler(int(*eh)(MsgEventQ_t *, MsgEvent_t *));static uint32_t yuv2rgb(uint32_t yuv_color){ int Y,Cb,Cr; int Ey, Epb, Epr; int Eg, Eb, Er; uint32_t result; Y = (yuv_color >> 16) & 0xff; Cb = (yuv_color ) & 0xff; Cr = (yuv_color >> 8 ) & 0xff; Ey = (Y-16); Epb = (Cb-128); Epr = (Cr-128); /* ITU-R 709 Eg = (298*Ey - 55*Epb - 137*Epr)/256; Eb = (298*Ey + 543*Epb)/256; Er = (298*Ey + 460*Epr)/256; */ /* FCC ~= mediaLib */ Eg = (298*Ey - 100*Epb - 208*Epr)/256; Eb = (298*Ey + 516*Epb)/256; Er = (298*Ey + 408*Epr)/256; if(Eg > 255) Eg = 255; if(Eg < 0) Eg = 0; if(Eb > 255) Eb = 255; if(Eb < 0) Eb = 0; if(Er > 255) Er = 255; if(Er < 0) Er = 0; if( rgbmode == MODE_BGR || rgbmode == MODE_RGB_ALIEN) { result = (Eb << 16) | (Eg << 8) | Er; } else { result = (Er << 16) | (Eg << 8) | Eb; } return result;}static int attach_stream_buffer(uint8_t stream_id, uint8_t subtype, int shmid){ char *shmaddr; q_head_t *q_head; //DNOTE("spu_mixer: shmid: %d\n", shmid); if(shmid >= 0) { if((shmaddr = shmat(shmid, NULL, SHM_SHARE_MMU)) == (void *)-1) { ERROR("%s", "spu_mixer: attach_decoder_buffer()"); perror("shmat"); return -1; } stream_shmid = shmid; stream_shmaddr = shmaddr; } q_head = (q_head_t *)stream_shmaddr; shmid = q_head->data_buf_shmid; if(shmid >= 0) { if((shmaddr = shmat(shmid, NULL, SHM_SHARE_MMU)) == (void *)-1) { ERROR("%s", "spu: attach_data_buffer()"); perror("shmat"); return -1; } data_buf_shmid = shmid; data_buf_shmaddr = shmaddr; } initialized = 1; return 0;}static int handle_events(MsgEventQ_t *q, MsgEvent_t *ev){ switch(ev->type) { case MsgEventQNotify: if((stream_shmaddr != NULL) && (ev->notify.qid == ((q_head_t *)stream_shmaddr)->qid)) { DPRINTF(1, "spu_mixer: got notification\n"); redraw_request(); } else { return 0; } break; case MsgEventQDecodeStreamBuf: DPRINTF(1, "video_decode: got stream %x, %x buffer \n", ev->decodestreambuf.stream_id, ev->decodestreambuf.subtype); attach_stream_buffer(ev->decodestreambuf.stream_id, ev->decodestreambuf.subtype, ev->decodestreambuf.q_shmid); break; case MsgEventQSPUPalette: { int n; /* Should have PTS or SCR I think */ for(n = 0; n < 16; n++) { palette_yuv[n] = ev->spupalette.colors[n]; palette_rgb[n] = yuv2rgb(palette_yuv[n]); } redraw_request(); } break; case MsgEventQSPUHighlight: { int n; /* Enable the highlight, should have PTS or scr I think */ spu_info.has_highlight = 1; highlight.x_start = ev->spuhighlight.x_start; highlight.y_start = ev->spuhighlight.y_start; highlight.x_end = ev->spuhighlight.x_end; highlight.y_end = ev->spuhighlight.y_end; for(n = 0; n < 4; n++) { highlight.color[n] = ev->spuhighlight.color[n]; } for(n = 0; n < 4; n++) { highlight.contrast[n] = ev->spuhighlight.contrast[n]; } redraw_request(); } break; default: /* DNOTE("spu_mixer: ignoring event type (%d)\n", ev->type); */ return 0; break; } return 1;}static int get_q(char *dst, int readlen, uint64_t *display_base_time, int *new_scr_nr){ MsgEvent_t ev; q_head_t *q_head; q_elem_t *q_elems; data_buf_head_t *data_head; data_elem_t *data_elems; data_elem_t *data_elem; int elem; uint8_t *data_buffer; uint8_t PTS_DTS_flags; uint64_t PTS; uint64_t DTS; int scr_nr; int off; int len; static int read_offset = 0; // clocktime_t pts_time; int cpy_len; q_head = (q_head_t *)stream_shmaddr; q_elems = (q_elem_t *)(stream_shmaddr+sizeof(q_head_t)); elem = q_head->read_nr; if(!read_offset) { if(!q_elems[elem].in_use) { q_head->reader_requests_notification = 1; if(!q_elems[elem].in_use) { return 0; } } //DNOTE("spu_mixer: get element\n"); } data_head = (data_buf_head_t *)data_buf_shmaddr; data_buffer = data_buf_shmaddr + data_head->buffer_start_offset; data_elems = (data_elem_t *)(data_buf_shmaddr+sizeof(data_buf_head_t)); data_elem = &data_elems[q_elems[elem].data_elem_index]; off = data_elem->packet_data_offset+1; len = data_elem->packet_data_len-1; PTS_DTS_flags = data_elem->PTS_DTS_flags; if(PTS_DTS_flags & 0x2) { PTS = data_elem->PTS; scr_nr = data_elem->scr_nr; *display_base_time = PTS; /* PTS_TO_CLOCKTIME(pts_time, PTS); calc_realtime_from_scrtime(display_base_time, &pts_time, &ctrl_time[scr_nr].sync_point); */ *new_scr_nr = scr_nr; } if(PTS_DTS_flags & 0x1) { DTS = data_elem->DTS; } //DNOTE("spu_mixer: len: %d\n", len); //DNOTE("spu_mixer: readlen: %d\n", readlen); //DNOTE("spu_mixer: read_offset: %d\n", read_offset); if((readlen + read_offset) < len) { if((PTS_DTS_flags & 0x2) && (readlen != 2)) { read_offset = 0; DNOTE("%s", "Invalid SPU packet?\n"); return -1; } } if((readlen + read_offset) > len) { cpy_len = len-read_offset; //DNOTE("spu_mixer: bigger than available\n"); } else { cpy_len = readlen; } //DNOTE("spu_mixer: cpy_len: %d\n", cpy_len); memcpy(dst, data_buffer + off + read_offset, cpy_len); if(cpy_len + read_offset == len) { read_offset = 0; } else { read_offset += cpy_len; } if(read_offset) { return cpy_len; } // release elem //DNOTE("spu_mixer: release element\n"); data_elem->in_use = 0; q_elems[elem].in_use = 0; if(q_head->writer_requests_notification) { q_head->writer_requests_notification = 0; ev.type = MsgEventQNotify; if(MsgSendEvent(msgq, q_head->writer, &ev, 0) == -1) { FATAL("%s", "spu_mixer: couldn't send notification\n"); exit(1); } } q_head->read_nr = (q_head->read_nr+1)%q_head->nr_of_qelems; return cpy_len;}int init_spu(void){ //DNOTE("spu_mixer: init\n"); spu_info.buffer = malloc(MAX_BUF_SIZE); spu_info.next_buffer = malloc(MAX_BUF_SIZE); if(spu_info.buffer == NULL || spu_info.next_buffer == NULL) { ERROR("%s", "init_spu\n"); perror("malloc"); } register_event_handler(handle_events); return 0;}static int get_data(uint8_t *databuf, int bufsize, uint64_t *dtime, int *scr_nr){ int r; static int bytes_to_read = 0; static int state = 0; static int spu_size; /* Make sure to have a buffer bigger than this */ /* if(bufsize < 2) { // databuf not big enough ERROR("buffer too small\n"); return -1; } */ if(bytes_to_read == 0) { // get first 2 bytes of spu (size of spu) bytes_to_read = 2; } if(state == 0) { while(bytes_to_read > 0) { r = get_q(&databuf[2-bytes_to_read], bytes_to_read, dtime, scr_nr); if(r > 0) { bytes_to_read -= r; } else if(r < 0) { perror("read"); state = 0; bytes_to_read = 0; return -1; } else if(r == 0) { /* no more elements in q at this moment */ //DNOTE("q empty, %d bytes read\n", 2-bytes_to_read); return 0; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -