📄 vobsub.c
字号:
*width = 704; break; case 0x2: *width = 352; break; case 0x3: *width = 352; *height /= 2; break; default: mp_msg(MSGT_VOBSUB,MSGL_WARN,"Vobsub: Unknown resolution %d \n", resolution); } if (langid && 0 <= sid && sid < 32) { unsigned char *tmp = block + 0x256 + sid * 6 + 2; langid[0] = tmp[0]; langid[1] = tmp[1]; langid[2] = 0; } if (rar_seek(fd, pgci_sector * sizeof(block), SEEK_SET) || rar_read(block, sizeof(block), 1, fd) != 1) mp_msg(MSGT_VOBSUB,MSGL_ERR, "VobSub: Can't read IFO PGCI\n"); else { unsigned long idx; unsigned long pgc_offset = block[0xc] << 24 | block[0xd] << 16 | block[0xe] << 8 | block[0xf]; for (idx = 0; idx < 16; ++idx) { unsigned char *p = block + pgc_offset + 0xa4 + 4 * idx; palette[idx] = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; } if(vob) vob->have_palette = 1; res = 0; } } rar_close(fd); } return res;}void *vobsub_open(const char *const name,const char *const ifo,const int force,void** spu){ vobsub_t *vob = malloc(sizeof(vobsub_t)); if(spu) *spu = NULL; if (vob) { char *buf; vob->custom = 0; vob->have_palette = 0; vob->orig_frame_width = 0; vob->orig_frame_height = 0; vob->spu_streams = NULL; vob->spu_streams_size = 0; vob->spu_streams_current = 0; vob->delay = 0; vob->forced_subs=0; buf = malloc((strlen(name) + 5) * sizeof(char)); if (buf) { rar_stream_t *fd; mpeg_t *mpg; /* read in the info file */ if(!ifo) { strcpy(buf, name); strcat(buf, ".ifo"); vobsub_parse_ifo(vob,buf, vob->palette, &vob->orig_frame_width, &vob->orig_frame_height, force, -1, NULL); } else vobsub_parse_ifo(vob,ifo, vob->palette, &vob->orig_frame_width, &vob->orig_frame_height, force, -1, NULL); /* read in the index */ strcpy(buf, name); strcat(buf, ".idx"); fd = rar_open(buf, "rb"); if (fd == NULL) { if(force) mp_msg(MSGT_VOBSUB,MSGL_ERR,"VobSub: Can't open IDX file\n"); else { free(buf); free(vob); return NULL; } } else { while (vobsub_parse_one_line(vob, fd) >= 0) /* NOOP */ ; rar_close(fd); } /* if no palette in .idx then use custom colors */ if ((vob->custom == 0)&&(vob->have_palette!=1)) vob->custom = 1; if (spu && vob->orig_frame_width && vob->orig_frame_height) *spu = spudec_new_scaled_vobsub(vob->palette, vob->cuspal, vob->custom, vob->orig_frame_width, vob->orig_frame_height); /* read the indexed mpeg_stream */ strcpy(buf, name); strcat(buf, ".sub"); mpg = mpeg_open(buf); if (mpg == NULL) { if(force) mp_msg(MSGT_VOBSUB,MSGL_ERR,"VobSub: Can't open SUB file\n"); else { free(buf); free(vob); return NULL; } } else { long last_pts_diff = 0; while (!mpeg_eof(mpg)) { off_t pos = mpeg_tell(mpg); if (mpeg_run(mpg) < 0) { if (!mpeg_eof(mpg)) mp_msg(MSGT_VOBSUB,MSGL_ERR,"VobSub: mpeg_run error\n"); break; } if (mpg->packet_size) { if ((mpg->aid & 0xe0) == 0x20) { unsigned int sid = mpg->aid & 0x1f; if (vobsub_ensure_spu_stream(vob, sid) >= 0) { packet_queue_t *queue = vob->spu_streams + sid; /* get the packet to fill */ if (queue->packets_size == 0 && packet_queue_grow(queue) < 0) abort(); while (queue->current_index + 1 < queue->packets_size && queue->packets[queue->current_index + 1].filepos <= pos) ++queue->current_index; if (queue->current_index < queue->packets_size) { packet_t *pkt; if (queue->packets[queue->current_index].data) { /* insert a new packet and fix the PTS ! */ packet_queue_insert(queue); queue->packets[queue->current_index].pts100 = mpg->pts + last_pts_diff; } pkt = queue->packets + queue->current_index; if (pkt->pts100 != UINT_MAX) { if (queue->packets_size > 1) last_pts_diff = pkt->pts100 - mpg->pts; else pkt->pts100 = mpg->pts; /* FIXME: should not use mpg_sub internal informations, make a copy */ pkt->data = mpg->packet; pkt->size = mpg->packet_size; mpg->packet = NULL; mpg->packet_reserve = 0; mpg->packet_size = 0; } } } else mp_msg(MSGT_VOBSUB,MSGL_WARN, "don't know what to do with subtitle #%u\n", sid); } } } vob->spu_streams_current = vob->spu_streams_size; while (vob->spu_streams_current-- > 0) vob->spu_streams[vob->spu_streams_current].current_index = 0; mpeg_free(mpg); } free(buf); } } return vob;}voidvobsub_close(void *this){ vobsub_t *vob = (vobsub_t *)this; if (vob->spu_streams) { while (vob->spu_streams_size--) packet_queue_destroy(vob->spu_streams + vob->spu_streams_size); free(vob->spu_streams); } free(vob);}unsigned intvobsub_get_indexes_count(void *vobhandle){ vobsub_t *vob = (vobsub_t *) vobhandle; return vob->spu_streams_size;}char *vobsub_get_id(void *vobhandle, unsigned int index){ vobsub_t *vob = (vobsub_t *) vobhandle; return (index < vob->spu_streams_size) ? vob->spu_streams[index].id : NULL;}unsigned int vobsub_get_forced_subs_flag(void const * const vobhandle){ if (vobhandle) return ((vobsub_t*) vobhandle)->forced_subs; else return 0;}intvobsub_set_from_lang(void *vobhandle, unsigned char * lang){ int i; vobsub_t *vob= (vobsub_t *) vobhandle; while(lang && strlen(lang) >= 2){ for(i=0; i < vob->spu_streams_size; i++) if (vob->spu_streams[i].id) if ((strncmp(vob->spu_streams[i].id, lang, 2)==0)){ vobsub_id=i; mp_msg(MSGT_VOBSUB, MSGL_INFO, "Selected VOBSUB language: %d language: %s\n", i, vob->spu_streams[i].id); return 0; } lang+=2;while (lang[0]==',' || lang[0]==' ') ++lang; } mp_msg(MSGT_VOBSUB, MSGL_WARN, "No matching VOBSUB language found!\n"); return -1;} intvobsub_get_packet(void *vobhandle, float pts,void** data, int* timestamp) { vobsub_t *vob = (vobsub_t *)vobhandle; unsigned int pts100 = 90000 * pts; if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { packet_queue_t *queue = vob->spu_streams + vobsub_id; while (queue->current_index < queue->packets_size) { packet_t *pkt = queue->packets + queue->current_index; if (pkt->pts100 != UINT_MAX) if (pkt->pts100 <= pts100) { ++queue->current_index; *data = pkt->data; *timestamp = pkt->pts100; return pkt->size; } else break; else ++queue->current_index; } } return -1;}intvobsub_get_next_packet(void *vobhandle, void** data, int* timestamp){ vobsub_t *vob = (vobsub_t *)vobhandle; if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { packet_queue_t *queue = vob->spu_streams + vobsub_id; if (queue->current_index < queue->packets_size) { packet_t *pkt = queue->packets + queue->current_index; ++queue->current_index; *data = pkt->data; *timestamp = pkt->pts100; return pkt->size; } } return -1;}void vobsub_seek(void * vobhandle, float pts){ vobsub_t * vob = (vobsub_t *)vobhandle; packet_queue_t * queue; int seek_pts100 = (int)pts * 90000; if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { /* do not seek if we don't know the id */ if (vobsub_get_id(vob, vobsub_id) == NULL) return; queue = vob->spu_streams + vobsub_id; queue->current_index = 0; while ((queue->packets + queue->current_index)->pts100 < seek_pts100) ++queue->current_index; if (queue->current_index > 0) --queue->current_index; }}voidvobsub_reset(void *vobhandle){ vobsub_t *vob = (vobsub_t *)vobhandle; if (vob->spu_streams) { unsigned int n = vob->spu_streams_size; while (n-- > 0) vob->spu_streams[n].current_index = 0; }}/********************************************************************** * Vobsub output **********************************************************************/typedef struct { FILE *fsub; FILE *fidx; unsigned int aid;} vobsub_out_t;static voidcreate_idx(vobsub_out_t *me, const unsigned int *palette, unsigned int orig_width, unsigned int orig_height){ int i; fprintf(me->fidx, "# VobSub index file, v7 (do not modify this line!)\n" "#\n" "# Generated by MPlayer " VERSION "\n" "# See <URL:http://www.mplayerhq.hu/> for more information about MPlayer\n" "# See <URL:http://vobsub.edensrising.com/> for more information about Vobsub\n" "#\n" "size: %ux%u\n", orig_width, orig_height); if (palette) { fputs("palette:", me->fidx); for (i = 0; i < 16; ++i) { const double y = palette[i] >> 16 & 0xff, u = (palette[i] >> 8 & 0xff) - 128.0, v = (palette[i] & 0xff) - 128.0; if (i) putc(',', me->fidx); fprintf(me->fidx, " %02x%02x%02x", MIN(MAX((int)(y + 1.4022 * u), 0), 0xff), MIN(MAX((int)(y - 0.3456 * u - 0.7145 * v), 0), 0xff), MIN(MAX((int)(y + 1.7710 * v), 0), 0xff)); } putc('\n', me->fidx); } fprintf(me->fidx,"# ON: displays only forced subtitles, OFF: shows everything\n" "forced subs: OFF\n");}void *vobsub_out_open(const char *basename, const unsigned int *palette, unsigned int orig_width, unsigned int orig_height, const char *id, unsigned int index){ vobsub_out_t *result = NULL; char *filename; filename = malloc(strlen(basename) + 5); if (filename) { result = malloc(sizeof(vobsub_out_t)); result->fsub = NULL; result->fidx = NULL; result->aid = 0; if (result) { result->aid = index; strcpy(filename, basename); strcat(filename, ".sub"); result->fsub = fopen(filename, "a"); if (result->fsub == NULL) perror("Error: vobsub_out_open subtitle file open failed"); strcpy(filename, basename); strcat(filename, ".idx"); result->fidx = fopen(filename, "a"); if (result->fidx) { if (ftell(result->fidx) == 0){ create_idx(result, palette, orig_width, orig_height); /* Make the selected language the default language */ fprintf(result->fidx, "\n# Language index in use\nlangidx: %u\n", index); } fprintf(result->fidx, "\nid: %s, index: %u\n", id ? id : "xx", index); /* So that we can check the file now */ fflush(result->fidx); } else perror("Error: vobsub_out_open index file open failed"); free(filename); } } return result;}voidvobsub_out_close(void *me){ vobsub_out_t *vob = (vobsub_out_t*)me; if (vob->fidx) fclose(vob->fidx); if (vob->fsub) fclose(vob->fsub); free(vob);}voidvobsub_out_output(void *me, const unsigned char *packet, int len, double pts){ static double last_pts; static int last_pts_set = 0; vobsub_out_t *vob = (vobsub_out_t*)me; if (vob->fsub) { /* Windows' Vobsub require that every packet is exactly 2kB long */ unsigned char buffer[2048]; unsigned char *p; int remain = 2048; /* Do not output twice a line with the same timestamp, this breaks Windows' Vobsub */ if (vob->fidx && (!last_pts_set || last_pts != pts)) { static unsigned int last_h = 9999, last_m = 9999, last_s = 9999, last_ms = 9999; unsigned int h, m, ms; double s; s = pts; h = s / 3600; s -= h * 3600; m = s / 60; s -= m * 60; ms = (s - (unsigned int) s) * 1000; if (ms >= 1000) /* prevent overfolws or bad float stuff */ ms = 0; if (h != last_h || m != last_m || (unsigned int) s != last_s || ms != last_ms) { fprintf(vob->fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: %09lx\n", h, m, (unsigned int) s, ms, ftell(vob->fsub)); last_h = h; last_m = m; last_s = (unsigned int) s; last_ms = ms; } } last_pts = pts; last_pts_set = 1; /* Packet start code: Windows' Vobsub needs this */ p = buffer; *p++ = 0; /* 0x00 */ *p++ = 0; *p++ = 1; *p++ = 0xba; *p++ = 0x40; memset(p, 0, 9); p += 9; { /* Packet */ static unsigned char last_pts[5] = { 0, 0, 0, 0, 0}; unsigned char now_pts[5]; int pts_len, pad_len, datalen = len; pts *= 90000; now_pts[0] = 0x21 | (((unsigned long)pts >> 29) & 0x0e); now_pts[1] = ((unsigned long)pts >> 22) & 0xff; now_pts[2] = 0x01 | (((unsigned long)pts >> 14) & 0xfe); now_pts[3] = ((unsigned long)pts >> 7) & 0xff; now_pts[4] = 0x01 | (((unsigned long)pts << 1) & 0xfe); pts_len = memcmp(last_pts, now_pts, sizeof(now_pts)) ? sizeof(now_pts) : 0; memcpy(last_pts, now_pts, sizeof(now_pts)); datalen += 3; /* Version, PTS_flags, pts_len */ datalen += pts_len; datalen += 1; /* AID */ pad_len = 2048 - (p - buffer) - 4 /* MPEG ID */ - 2 /* payload len */ - datalen; /* XXX - Go figure what should go here! In any case the packet has to be completly filled. If I can fill it with padding (0x000001be) latter I'll do that. But if there is only room for 6 bytes then I can not write a padding packet. So I add some padding in the PTS field. This looks like a dirty kludge. Oh well... */ if (pad_len < 0) { /* Packet is too big. Let's try ommiting the PTS field */ datalen -= pts_len; pts_len = 0; pad_len = 0; } else if (pad_len > 6) pad_len = 0; datalen += pad_len; *p++ = 0; /* 0x0e */ *p++ = 0; *p++ = 1; *p++ = 0xbd; *p++ = (datalen >> 8) & 0xff; /* length of payload */ *p++ = datalen & 0xff; *p++ = 0x80; /* System-2 (.VOB) stream */ *p++ = pts_len ? 0x80 : 0x00; /* pts_flags */ *p++ = pts_len + pad_len; memcpy(p, now_pts, pts_len); p += pts_len; memset(p, 0, pad_len); p += pad_len; } *p++ = 0x20 | vob->aid; /* aid */ if (fwrite(buffer, p - buffer, 1, vob->fsub) != 1 || fwrite(packet, len, 1, vob->fsub) != 1) perror("ERROR: vobsub write failed"); else remain -= p - buffer + len; /* Padding */ if (remain >= 6) { p = buffer; *p++ = 0x00; *p++ = 0x00; *p++ = 0x01; *p++ = 0xbe; *p++ = (remain - 6) >> 8; *p++ = (remain - 6) & 0xff; /* for better compression, blank this */ memset(buffer + 6, 0, remain - (p - buffer)); if (fwrite(buffer, remain, 1, vob->fsub) != 1) perror("ERROR: vobsub padding write failed"); } else if (remain > 0) { /* I don't know what to output. But anyway the block needs to be 2KB big */ memset(buffer, 0, remain); if (fwrite(buffer, remain, 1, vob->fsub) != 1) perror("ERROR: vobsub blank padding write failed"); } else if (remain < 0) fprintf(stderr, "\nERROR: wrong thing happenned...\n" " I wrote a %i data bytes spu packet and that's too long\n", len); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -