📄 spudec.c
字号:
this->palette[0] = this->packet[off] >> 4; this->palette[1] = this->packet[off] & 0xf; this->palette[2] = this->packet[off + 1] >> 4; this->palette[3] = this->packet[off + 1] & 0xf; mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Palette %d, %d, %d, %d\n", this->palette[0], this->palette[1], this->palette[2], this->palette[3]); off+=2; break; case 0x04: /* Alpha */ this->alpha[0] = this->packet[off] >> 4; this->alpha[1] = this->packet[off] & 0xf; this->alpha[2] = this->packet[off + 1] >> 4; this->alpha[3] = this->packet[off + 1] & 0xf; mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Alpha %d, %d, %d, %d\n", this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]); off+=2; break; case 0x05: /* Co-ords */ a = get_be24(this->packet + off); b = get_be24(this->packet + off + 3); start_col = a >> 12; end_col = a & 0xfff; width = (end_col < start_col) ? 0 : end_col - start_col + 1; stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */ start_row = b >> 12; end_row = b & 0xfff; height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */; mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Coords col: %d - %d row: %d - %d (%dx%d)\n", start_col, end_col, start_row, end_row, width, height); off+=6; break; case 0x06: /* Graphic lines */ current_nibble[0] = 2 * get_be16(this->packet + off); current_nibble[1] = 2 * get_be16(this->packet + off + 2); mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Graphic offset 1: %d offset 2: %d\n", current_nibble[0] / 2, current_nibble[1] / 2); off+=4; break; case 0xff: /* All done, bye-bye */ mp_msg(MSGT_SPUDEC,MSGL_DBG2,"Done!\n"); return;// break; default: mp_msg(MSGT_SPUDEC,MSGL_WARN,"spudec: Error determining control type 0x%02x. Skipping %d bytes.\n", type, next_off - off); goto next_control; } } next_control: if (display) { packet_t *packet = calloc(1, sizeof(packet_t)); int i; packet->start_pts = start_pts; if (end_pts == UINT_MAX && start_off != next_off) { start_pts = pts100 + get_be16(this->packet + next_off) * 1024; packet->end_pts = start_pts - 1; } else packet->end_pts = end_pts; packet->current_nibble[0] = current_nibble[0]; packet->current_nibble[1] = current_nibble[1]; packet->start_row = start_row; packet->end_row = end_row; packet->start_col = start_col; packet->end_col = end_col; packet->width = width; packet->height = height; packet->stride = stride; packet->control_start = control_start; for (i=0; i<4; i++) { packet->alpha[i] = this->alpha[i]; packet->palette[i] = this->palette[i]; } packet->packet = malloc(this->packet_size); memcpy(packet->packet, this->packet, this->packet_size); spudec_queue_packet(this, packet); } }}static void spudec_decode(spudec_handle_t *this, unsigned int pts100){ if(this->hw_spu) { static vo_mpegpes_t packet = { NULL, 0, 0x20, 0 }; static vo_mpegpes_t *pkg=&packet; packet.data = this->packet; packet.size = this->packet_size; packet.timestamp = pts100; this->hw_spu->draw_frame((uint8_t**)&pkg); } else spudec_process_control(this, pts100);}int spudec_changed(void * this){ spudec_handle_t * spu = (spudec_handle_t*)this; return (spu->spu_changed || spu->now_pts > spu->end_pts);}void spudec_assemble(void *this, unsigned char *packet, unsigned int len, unsigned int pts100){ spudec_handle_t *spu = (spudec_handle_t*)this;// spudec_heartbeat(this, pts100); if (len < 2) { mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: packet too short\n"); return; } if ((spu->packet_pts + 10000) < pts100) { // [cb] too long since last fragment: force new packet spu->packet_offset = 0; } spu->packet_pts = pts100; if (spu->packet_offset == 0) { unsigned int len2 = get_be16(packet); // Start new fragment if (spu->packet_reserve < len2) { if (spu->packet != NULL) free(spu->packet); spu->packet = malloc(len2); spu->packet_reserve = spu->packet != NULL ? len2 : 0; } if (spu->packet != NULL) { spu->packet_size = len2; if (len > len2) { mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid frag len / len2: %d / %d \n", len, len2); return; } memcpy(spu->packet, packet, len); spu->packet_offset = len; spu->packet_pts = pts100; } } else { // Continue current fragment if (spu->packet_size < spu->packet_offset + len){ mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUasm: invalid fragment\n"); spu->packet_size = spu->packet_offset = 0; return; } else { memcpy(spu->packet + spu->packet_offset, packet, len); spu->packet_offset += len; } }#if 1 // check if we have a complete packet (unfortunatelly packet_size is bad // for some disks) // [cb] packet_size is padded to be even -> may be one byte too long if ((spu->packet_offset == spu->packet_size) || ((spu->packet_offset + 1) == spu->packet_size)){ unsigned int x=0,y; while(x+4<=spu->packet_offset){ y=get_be16(spu->packet+x+2); // next control pointer mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUtest: x=%d y=%d off=%d size=%d\n",x,y,spu->packet_offset,spu->packet_size); if(x>=4 && x==y){ // if it points to self - we're done! // we got it! mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPUgot: off=%d size=%d \n",spu->packet_offset,spu->packet_size); spudec_decode(spu, pts100); spu->packet_offset = 0; break; } if(y<=x || y>=spu->packet_size){ // invalid? mp_msg(MSGT_SPUDEC,MSGL_WARN,"SPUtest: broken packet!!!!! y=%d < x=%d\n",y,x); spu->packet_size = spu->packet_offset = 0; break; } x=y; } // [cb] packet is done; start new packet spu->packet_offset = 0; }#else if (spu->packet_offset == spu->packet_size) { spudec_decode(spu, pts100); spu->packet_offset = 0; }#endif}void spudec_reset(void *this) // called after seek{ spudec_handle_t *spu = (spudec_handle_t*)this; while (spu->queue_head) spudec_free_packet(spudec_dequeue_packet(spu)); spu->now_pts = 0; spu->end_pts = 0; spu->packet_size = spu->packet_offset = 0;}void spudec_heartbeat(void *this, unsigned int pts100){ spudec_handle_t *spu = (spudec_handle_t*) this; spu->now_pts = pts100; while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) { packet_t *packet = spudec_dequeue_packet(spu); spu->start_pts = packet->start_pts; spu->end_pts = packet->end_pts; if (spu->auto_palette) compute_palette(spu, packet); spudec_process_data(spu, packet); spudec_free_packet(packet); spu->spu_changed = 1; }}int spudec_visible(void *this){ spudec_handle_t *spu = (spudec_handle_t *)this; int ret=(spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->height > 0);// printf("spu visible: %d \n",ret); return ret;}void spudec_set_forced_subs_only(void * const this, const unsigned int flag){ if(this){ ((spudec_handle_t *)this)->forced_subs_only=flag; mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU: Display only forced subs now %s\n", flag ? "enabled": "disabled"); }}void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){ spudec_handle_t *spu = (spudec_handle_t *)this; if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image) { draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height, spu->image, spu->aimage, spu->stride); spu->spu_changed = 0; }}/* calc the bbox for spudec subs */void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox){ spudec_handle_t *spu; spu = (spudec_handle_t *)me; if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) { bbox[0] = spu->start_col; bbox[1] = spu->start_col + spu->width; bbox[2] = spu->start_row; bbox[3] = spu->start_row + spu->height; } else if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { unsigned int scalex = 0x100 * dxs / spu->orig_frame_width; unsigned int scaley = 0x100 * dys / spu->orig_frame_height; bbox[0] = spu->start_col * scalex / 0x100; bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100; switch (spu_alignment) { case 0: bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100; if (bbox[3] > dys) bbox[3] = dys; bbox[2] = bbox[3] - spu->height * scaley / 0x100; break; case 1: if (sub_pos < 50) { bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200; if (bbox[2] < 0) bbox[2] = 0; bbox[3] = bbox[2] + spu->height; } else { bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200; if (bbox[3] > dys) bbox[3] = dys; bbox[2] = bbox[3] - spu->height * scaley / 0x100; } break; case 2: bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100; if (bbox[2] < 0) bbox[2] = 0; bbox[3] = bbox[2] + spu->height; break; default: /* -1 */ bbox[2] = spu->start_row * scaley / 0x100; bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100; break; } }}/* transform mplayer's alpha value into an opacity value that is linear */static inline int canon_alpha(int alpha){ return alpha ? 256 - alpha : 0;}typedef struct { unsigned position; unsigned left_up; unsigned right_down;}scale_pixel;static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table){ unsigned int t; unsigned int delta_src = end_src - start_src; unsigned int delta_tar = end_tar - start_tar; int src = 0; int src_step; if (delta_src == 0 || delta_tar == 0) { return; } src_step = (delta_src << 16) / delta_tar >>1; for (t = 0; t<=delta_tar; src += (src_step << 1), t++){ table[t].position= MIN(src >> 16, end_src - 1); table[t].right_down = src & 0xffff; table[t].left_up = 0x10000 - table[t].right_down; }}/* bilinear scale, similar to vobsub's code */static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu){ int alpha[4]; int color[4]; unsigned int scale[4]; int base = table_y[y].position * spu->stride + table_x[x].position; int scaled = y * spu->scaled_stride + x; alpha[0] = canon_alpha(spu->aimage[base]); alpha[1] = canon_alpha(spu->aimage[base + 1]); alpha[2] = canon_alpha(spu->aimage[base + spu->stride]); alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]); color[0] = spu->image[base]; color[1] = spu->image[base + 1]; color[2] = spu->image[base + spu->stride]; color[3] = spu->image[base + spu->stride + 1]; scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0]; scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1]; scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2]; scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3]; spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24; spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16; if (spu->scaled_aimage[scaled]){ spu->scaled_aimage[scaled] = 256 - spu->scaled_aimage[scaled]; if(spu->scaled_aimage[scaled] + spu->scaled_image[scaled] > 255) spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled]; }}void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, int ds, unsigned char *s1, unsigned char *s2, int sw, int sh, int ss){/* struct SwsContext *ctx; static SwsFilter filter; static int firsttime = 1; static float oldvar; int i; if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH); if (firsttime) { filter.lumH = filter.lumV = filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0); sws_normalizeVec(filter.lumH, 1.0); firsttime = 0; oldvar = spu_gaussvar; } ctx=sws_getContext(sw, sh, IMGFMT_Y800, dw, dh, IMGFMT_Y800, SWS_GAUSS, &filter, NULL, NULL); sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds); for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1; sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds); for (i=ds*dh-1; i>=0; i--) if (d2[i]==0) d2[i] = 1; else if (d2[i]==255) d2[i] = 0; sws_freeContext(ctx);*/}void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){ spudec_handle_t *spu = (spudec_handle_t *)me; scale_pixel *table_x; scale_pixel *table_y; if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) { // check if only forced subtitles are requested if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){ return; } if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0 || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) { if (spu->image) { draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height, spu->image, spu->aimage, spu->stride); spu->spu_changed = 0; } } else { if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */ /* scaled_x = scalex * x / 0x100 scaled_y = scaley * y / 0x100 order of operations is important because of rounding. */ unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -