📄 spudec.c
字号:
/* SPUdec.c Skeleton of function spudec_process_controll() is from xine sources. Further works: LGB,... (yeah, try to improve it and insert your name here! ;-) Kim Minh Kaplan implement fragments reassembly, RLE decoding. read brightness from the IFO. For information on SPU format see <URL:http://sam.zoy.org/doc/dvd/subtitles/> and <URL:http://members.aol.com/mpucoder/DVD/spu.html> */#include "config.h"#include "mp_msg.h"#include <errno.h>#include <limits.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <math.h>#include "libvo/video_out.h"#include "spudec.h"//#include "postproc/swscale.h"#define MIN(a, b) ((a)<(b)?(a):(b))/* Valid values for spu_aamode: 0: none (fastest, most ugly) 1: approximate 2: full (slowest) 3: bilinear (similiar to vobsub, fast and not too bad) 4: uses swscaler gaussian (this is the only one that looks good) */int spu_aamode = 3;int spu_alignment = -1;float spu_gaussvar = 1.0;extern int sub_pos;typedef struct packet_t packet_t;struct packet_t { unsigned char *packet; unsigned int palette[4]; unsigned int alpha[4]; unsigned int control_start; /* index of start of control data */ unsigned int current_nibble[2]; /* next data nibble (4 bits) to be processed (for RLE decoding) for even and odd lines */ int deinterlace_oddness; /* 0 or 1, index into current_nibble */ unsigned int start_col, end_col; unsigned int start_row, end_row; unsigned int width, height, stride; unsigned int start_pts, end_pts; packet_t *next;};typedef struct { packet_t *queue_head; packet_t *queue_tail; unsigned int global_palette[16]; unsigned int orig_frame_width, orig_frame_height; unsigned char* packet; size_t packet_reserve; /* size of the memory pointed to by packet */ unsigned int packet_offset; /* end of the currently assembled fragment */ unsigned int packet_size; /* size of the packet once all fragments are assembled */ unsigned int packet_pts; /* PTS for this packet */ unsigned int palette[4]; unsigned int alpha[4]; unsigned int cuspal[4]; unsigned int custom; unsigned int now_pts; unsigned int start_pts, end_pts; unsigned int start_col, end_col; unsigned int start_row, end_row; unsigned int width, height, stride; size_t image_size; /* Size of the image buffer */ unsigned char *image; /* Grayscale value */ unsigned char *aimage; /* Alpha value */ unsigned int scaled_frame_width, scaled_frame_height; unsigned int scaled_start_col, scaled_start_row; unsigned int scaled_width, scaled_height, scaled_stride; size_t scaled_image_size; unsigned char *scaled_image; unsigned char *scaled_aimage; int auto_palette; /* 1 if we lack a palette and must use an heuristic. */ int font_start_level; /* Darkest value used for the computed font */ vo_functions_t *hw_spu; int spu_changed; unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */ unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */} spudec_handle_t;static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet){ if (this->queue_head == NULL) this->queue_head = packet; else this->queue_tail->next = packet; this->queue_tail = packet;}static packet_t *spudec_dequeue_packet(spudec_handle_t *this){ packet_t *retval = this->queue_head; this->queue_head = retval->next; if (this->queue_head == NULL) this->queue_tail = NULL; return retval;}static void spudec_free_packet(packet_t *packet){ if (packet->packet != NULL) free(packet->packet); free(packet);}static inline unsigned int get_be16(const unsigned char *p){ return (p[0] << 8) + p[1];}static inline unsigned int get_be24(const unsigned char *p){ return (get_be16(p) << 8) + p[2];}static void next_line(packet_t *packet){ if (packet->current_nibble[packet->deinterlace_oddness] % 2) packet->current_nibble[packet->deinterlace_oddness]++; packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;}static inline unsigned char get_nibble(packet_t *packet){ unsigned char nib; unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness; if (*nibblep / 2 >= packet->control_start) { mp_msg(MSGT_SPUDEC,MSGL_WARN, "SPUdec: ERROR: get_nibble past end of packet\n"); return 0; } nib = packet->packet[*nibblep / 2]; if (*nibblep % 2) nib &= 0xf; else nib >>= 4; ++*nibblep; return nib;}static inline int mkalpha(int i){ /* In mplayer's alpha planes, 0 is transparent, then 1 is nearly opaque upto 255 which is transparent */ switch (i) { case 0xf: return 1; case 0: return 0; default: return (0xf - i) << 4; }}/* Cut the sub to visible part */static inline void spudec_cut_image(spudec_handle_t *this){ unsigned int fy, ly; unsigned int first_y, last_y; unsigned char *image; unsigned char *aimage; if (this->stride == 0 || this->height == 0) { return; } for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++); for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--); first_y = fy / this->stride; last_y = ly / this->stride; //printf("first_y: %d, last_y: %d\n", first_y, last_y); this->start_row += first_y; // Some subtitles trigger this condition if (last_y + 1 > first_y ) { this->height = last_y - first_y +1; } else { this->height = 0; this->image_size = 0; return; } // printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride); image = malloc(2 * this->stride * this->height); if(image){ this->image_size = this->stride * this->height; aimage = image + this->image_size; memcpy(image, this->image + this->stride * first_y, this->image_size); memcpy(aimage, this->aimage + this->stride * first_y, this->image_size); free(this->image); this->image = image; this->aimage = aimage; } else { mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height); }}static void spudec_process_data(spudec_handle_t *this, packet_t *packet){ unsigned int cmap[4], alpha[4]; unsigned int i, x, y; this->scaled_frame_width = 0; this->scaled_frame_height = 0; this->start_col = packet->start_col; this->end_col = packet->end_col; this->start_row = packet->start_row; this->end_row = packet->end_row; this->height = packet->height; this->width = packet->width; this->stride = packet->stride; for (i = 0; i < 4; ++i) { alpha[i] = mkalpha(packet->alpha[i]); if (alpha[i] == 0) cmap[i] = 0; else if (this->custom){ cmap[i] = ((this->cuspal[i] >> 16) & 0xff); if (cmap[i] + alpha[i] > 255) cmap[i] = 256 - alpha[i]; } else { cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff); if (cmap[i] + alpha[i] > 255) cmap[i] = 256 - alpha[i]; } } if (this->image_size < this->stride * this->height) { if (this->image != NULL) { free(this->image); this->image_size = 0; } this->image = malloc(2 * this->stride * this->height); if (this->image) { this->image_size = this->stride * this->height; this->aimage = this->image + this->image_size; } } if (this->image == NULL) return; /* Kludge: draw_alpha needs width multiple of 8. */ if (this->width < this->stride) for (y = 0; y < this->height; ++y) { memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width); /* FIXME: Why is this one needed? */ memset(this->image + y * this->stride + this->width, 0, this->stride - this->width); } i = packet->current_nibble[1]; x = 0; y = 0; while (packet->current_nibble[0] < i && packet->current_nibble[1] / 2 < packet->control_start && y < this->height) { unsigned int len, color; unsigned int rle = 0; rle = get_nibble(packet); if (rle < 0x04) { rle = (rle << 4) | get_nibble(packet); if (rle < 0x10) { rle = (rle << 4) | get_nibble(packet); if (rle < 0x040) { rle = (rle << 4) | get_nibble(packet); if (rle < 0x0004) rle |= ((this->width - x) << 2); } } } color = 3 - (rle & 0x3); len = rle >> 2; if (len > this->width - x || len == 0) len = this->width - x; /* FIXME have to use palette and alpha map*/ memset(this->image + y * this->stride + x, cmap[color], len); memset(this->aimage + y * this->stride + x, alpha[color], len); x += len; if (x >= this->width) { next_line(packet); x = 0; ++y; } } spudec_cut_image(this);}/* This function tries to create a usable palette. It determines how many non-transparent colors are used, and assigns differentgray scale values to each color. I tested it with four streams and even got something readable. Half of thetimes I got black characters with white around and half the reverse.*/static void compute_palette(spudec_handle_t *this, packet_t *packet){ int used[16],i,cused,start,step,color; memset(used, 0, sizeof(used)); for (i=0; i<4; i++) if (packet->alpha[i]) /* !Transparent? */ used[packet->palette[i]] = 1; for (cused=0, i=0; i<16; i++) if (used[i]) cused++; if (!cused) return; if (cused == 1) { start = 0x80; step = 0; } else { start = this->font_start_level; step = (0xF0-this->font_start_level)/(cused-1); } memset(used, 0, sizeof(used)); for (i=0; i<4; i++) { color = packet->palette[i]; if (packet->alpha[i] && !used[color]) { /* not assigned? */ used[color] = 1; this->global_palette[color] = start<<16; start += step; } }}static void spudec_process_control(spudec_handle_t *this, unsigned int pts100){ int a,b; /* Temporary vars */ unsigned int date, type; unsigned int off; unsigned int start_off = 0; unsigned int next_off; unsigned int start_pts; unsigned int end_pts; unsigned int current_nibble[2]; unsigned int control_start; unsigned int display = 0; unsigned int start_col = 0; unsigned int end_col = 0; unsigned int start_row = 0; unsigned int end_row = 0; unsigned int width = 0; unsigned int height = 0; unsigned int stride = 0; control_start = get_be16(this->packet + 2); next_off = control_start; while (start_off != next_off) { start_off = next_off; date = get_be16(this->packet + start_off) * 1024; next_off = get_be16(this->packet + start_off + 2); mp_msg(MSGT_SPUDEC,MSGL_DBG2, "date=%d\n", date); off = start_off + 4; for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) { mp_msg(MSGT_SPUDEC,MSGL_DBG2, "cmd=%d ",type); switch(type) { case 0x00: /* Menu ID, 1 byte */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Menu ID\n"); /* shouldn't a Menu ID type force display start? */ start_pts = pts100 + date; end_pts = UINT_MAX; display = 1; this->is_forced_sub=~0; // current subtitle is forced break; case 0x01: /* Start display */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Start display!\n"); start_pts = pts100 + date; end_pts = UINT_MAX; display = 1; this->is_forced_sub=0; break; case 0x02: /* Stop display */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Stop display!\n"); end_pts = pts100 + date; break; case 0x03: /* Palette */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -