2
// C++ Implementation:Spudecoder (subs for DVd like stream)
7
// Author: Mean, fixounet@free.fr
9
// Copyright: See COPYING file that comes with this distribution
11
// see http://sam.zoy.org/writings/dvd/subtitles/
14
/***************************************************************************
16
* This program is free software; you can redistribute it and/or modify *
17
* it under the terms of the GNU General Public License as published by *
18
* the Free Software Foundation; either version 2 of the License, or *
19
* (at your option) any later version. *
21
***************************************************************************/
27
#include <ADM_assert.h>
37
#include "ADM_toolkit/toolkit.hxx"
38
#include "ADM_editor/ADM_edit.hxx"
39
#include "ADM_video/ADM_genvideo.hxx"
40
#include "ADM_video/ADM_vidFlipV.h"
41
#include "ADM_filter/video_filters.h"
43
#include "ADM_mpeg2dec/ADM_mpegpacket.h"
44
#include "ADM_mpeg2dec/ADM_mpegpacket_PS.h"
46
#include "ADM_toolkit/filesel.h"
48
#include "ADM_colorspace/colorspace.h"
50
#include "ADM_vobsubinfo.h"
52
#define VOBSUB "/capture/sub/phone.sub"
54
#include "ADM_vidVobSub.h"
56
#include "ADM_toolkit/ADM_debugID.h"
57
#define MODULE_NAME MODULE_FILTER
58
#include "ADM_toolkit/ADM_debug.h"
61
extern uint8_t DIA_vobsub(vobSubParam *param);
63
static FILTER_PARAM vobsubParam={1,{"subname"}};
64
//*************************************************************
67
//*************************************************************
68
SCRIPT_CREATE(vobsub_script,ADMVideoVobSub,vobsubParam);
69
BUILD_CREATE(vobsub_create,ADMVideoVobSub);
70
//*************************************************************
71
uint8_t ADMVideoVobSub::configure(AVDMGenericVideoStream *in)
75
if(DIA_vobsub(_param))
85
//*************************************************************
86
char *ADMVideoVobSub::printConf( void )
90
sprintf((char *)buf," VobSub");
93
//*************************************************************
94
ADMVideoVobSub::ADMVideoVobSub( AVDMGenericVideoStream *in,CONFcouple *couples)
98
memcpy(&_info,_in->getInfo(),sizeof(_info));
102
_chromaResampled=NULL;
105
_param=NEW(vobSubParam);
116
_param->subname=ADM_strdup(VOBSUB);
118
_param->subname =NULL;
127
Alternate constructor for use by OCR
129
ADMVideoVobSub::ADMVideoVobSub( char *fileidx,uint32_t idx)
133
memset(&_info,0,sizeof(_info));
137
_chromaResampled=NULL;
140
_param=NEW(vobSubParam);
143
_param->subname=ADM_strdup(fileidx);
150
Returns bitmap & info for the Nth subs
153
vobSubBitmap *ADMVideoVobSub::getBitmap(uint32_t nb,uint32_t *start, uint32_t *end,uint32_t *first,uint32_t *last)
155
uint32_t top=0,bottom=0;
156
ADM_assert(_vobSubInfo);
157
ADM_assert(nb<_vobSubInfo->nbLines);
160
_parser->_asyncJump2(0,_vobSubInfo->lines[nb].fileOffset);
163
printf("Error reading getBimap\n");
165
return _original; // might be null (?)
171
_original->buildYUV(_YUVPalette);
172
ox=_original->_width;
173
oy=_original->_height;
174
printf("Original :%lu x %lu\n",ox,oy);
175
ADM_assert(oy<=_vobSubInfo->height);
177
// Search the 1st/last non null line
183
while(top<oy && !_original->isDirty(top)) top++;
187
top=bottom=0; // Empty bitmap ?
193
while(bottom>top && !_original->isDirty(bottom)) bottom--;
195
// If true it means we have 2 subs, one on top, one on bottom
198
if(bottom>(oy>>1) && top<(oy>>1) && (bottom-top>(oy>>1)))
200
// in that case, take only the lower one
202
while(top<oy && !_original->isDirty(top)) top++;
204
printf("> clipped: %lu / %lu=%lu\n",top,bottom,bottom-top+1);
210
*start=_vobSubInfo->lines[nb].startTime;
211
*end=_vobSubInfo->lines[nb].stopTime;
215
Returns the nb of lines found in the sub
217
uint32_t ADMVideoVobSub::getNbImage( void)
219
if(!_parser) return 0;
220
if(!_param) return 0;
221
if(!_vobSubInfo) return 0;
222
return _vobSubInfo->nbLines;
225
//************************************
226
uint8_t ADMVideoVobSub::setup(void)
232
if(_param->subname && strlen(_param->subname)>5)
234
printf("Opening %s\n",_param->subname);
235
dup=ADM_strdup(_param->subname);
245
if(vobSubRead(_param->subname,_param->index,&_vobSubInfo))
247
printf("Opening index \n");
250
_parser=new ADM_mpegDemuxerProgramStream(_param->index+0x20,0xe0);
252
if(!_parser->open(dup))
254
printf("Mpeg Parser : opening %s failed\n",_param->subname);
267
printf("opening of vobsub file failed\n");
270
{ // Recompute sub duration
272
vobSubLine *cur,*next;
273
// Assuming max displat time = MAX_DISPLAY_TIME
274
for(uint32_t i=0;i<_vobSubInfo->nbLines-1;i++)
276
if(i && !_vobSubInfo->lines[i].startTime)
278
_vobSubInfo->lines[i].startTime=0xf0000000;
279
_vobSubInfo->lines[i].stopTime=0xf0000001;
284
cur=&_vobSubInfo->lines[i];
285
next=&_vobSubInfo->lines[i+1];
287
end=cur->startTime+MAX_DISPLAY_TIME;
288
if(end>=next->startTime) end=next->startTime-1;
292
_vobSubInfo->lines[_vobSubInfo->nbLines-1].stopTime=
293
MAX_DISPLAY_TIME+_vobSubInfo->lines[_vobSubInfo->nbLines-1].startTime;
294
// Convert all the palette from RGB to YUV
299
_data=new uint8_t [VS_MAXPACKET];
303
memset(&_original,0,sizeof(_original));
309
//*************************************************************
310
uint8_t ADMVideoVobSub::cleanup(void)
313
if(_parser) delete _parser;
325
delete _chromaResampled;
326
_chromaResampled=NULL;
329
if(_data) delete [] _data;
332
if(_vobSubInfo) destroySubInfo( _vobSubInfo);
337
//*************************************************************
338
ADMVideoVobSub::~ADMVideoVobSub()
343
if(_param->subname) ADM_dealloc(_param->subname);
349
//*************************************************************
350
uint8_t ADMVideoVobSub::getCoupledConf( CONFcouple **couples)
353
*couples=new CONFcouple(3);
355
#define CSET(x) (*couples)->setCouple((char *)#x,(_param->x))
359
(*couples)->setCouple("subname","none") ;
366
//*************************************************************
367
uint8_t ADMVideoVobSub::getFrameNumberNoAlloc(uint32_t frame,
376
ADM_assert(frame<_info.nb_frames);
377
// read uncompressed frame
378
if(!_in->getFrameNumberNoAlloc(frame, len,data,flags)) return 0;
383
printf("No valid vobsub to process\n");
389
time=(frame+_info.orgFrame);
390
time=(time*1000*1000)/_info.fps1000;
393
// Should we re-use the current one ?
396
aprintf("No matching sub for time %llu frame%lu\n",time,frame);
399
// If it is a new sub, decode it...
400
if(sub!=_currentSub )
402
_parser->_asyncJump2(0,_vobSubInfo->lines[sub].fileOffset);
403
_initialPts=_parser->getPTS();
406
Palettte2Display(); // Create the bitmap
407
// Time to resize the bitmap
408
// First try : Do it bluntly
412
// and if there is something to display, display it
421
aprintf("We have %lu %lu to merge\n",src->_width,src->_height);
424
uint32_t stridein,strideout,len;
425
uint8_t *in,*out,*mask,*in2;
429
stridein=src->_width;
430
strideout=_info.width;
432
if(strideout>stridein)
442
if(src->_height>_info.height) yy=_info.height;
443
else yy=src->_height;
445
mask=src->_alphaMask;
447
out=data->data+_info.width*src->placeTop;
449
uint32_t center=_info.width-src->_width;
452
for(uint32_t y=0;y<yy;y++)
454
for(uint32_t x=0;x<xx;x++)
462
if(alp>7) nw=old*(16-alp-1)+(alp+1)*nw;
463
else nw=old*(16-alp)+(alp)*nw;
469
//memcpy(out,in,len);
475
// Now do chroma u & chroma V
477
#if defined(DOCHROMA)
478
uint32_t crosspage=(_info.width*_info.height)>>2;
480
strideout=_info.width>>1;
481
stridein=_chromaResampled->_width;
483
out=data->data+_info.width*_info.height;
484
out+=(src->placeTop>>1)*(_info.width>>1);
485
mask=_chromaResampled->_alphaMask;
488
if(strideout>stridein) xx=stridein;
491
int16_t left=(_info.height>>1)-(_chromaResampled->_height+(_original->placeTop>>1));
493
if(left<_chromaResampled->_height) yy=left;
494
else yy=_chromaResampled->_height;
496
for(uint32_t y=0;y<yy;y++)
498
for(uint32_t x=0;x<xx;x++)
514
out[crosspage+x]=val;
524
//*************************************************************************
526
// Convert the original bitmap to a rescaled & repositionned one
527
// that will be blended into the current picutr
529
//*************************************************************************
530
uint8_t ADMVideoVobSub::Palettte2Display( void )
533
ADM_assert(_vobSubInfo);
535
// Then Process the RLE Datas
536
// To get the _bitmap yuv data
537
ADM_assert(_original);
540
_original->buildYUV(_YUVPalette);
542
// rebuild the scaled one
543
// Compute the target size
548
Fx, fy : Final size of the image (i.e size of the current picture)
549
ox,oy : Original size of the image where the sub is coming from
550
sx,sy : Size of the sub
552
And we want the final size of the sub
553
+ coordinates but that we will do later
560
ox=_vobSubInfo->width;
561
oy=_vobSubInfo->height;
566
// Search the 1st/last non null line
567
uint32_t top=0,bottom=0;
568
while(top<oy && !_original->isDirty(top)) top++;
570
bottom=_original->_height-1;
571
while(bottom && !_original->isDirty(bottom)) bottom--;
573
// If true it means we have 2 subs, one on top, one on bottom
575
if(bottom>(oy>>1) && top<(oy>>1) && (bottom-top>(oy>>1)))
577
// in that case, take only the lower one
579
while(top<oy && !_original->isDirty(top)) top++;
582
// The useful part is between top & bottom lines
586
// The shrink factor is the one used to shrink from the original video
587
// to the resize video
592
printf("top %lu : bottom :%lu Scale :%f ox:%lu oy:%lu fx:%lu \n",top,bottom,scale,ox,oy,fx);
594
// We rescale the sub by the same factor
595
// Only the visible / useful part
598
sx=(uint32_t )floor(l);
603
sy=(uint32_t )floor(l);
606
// And we resize that useful part of sub
607
// to our final bitmap (resampled)
609
_original->subResize(&_resampled,sx,sy,top, bottom-top);
613
// Set the position of the sub so that it is ok
623
_resampled->placeTop=tail;
625
_resampled->subResize(&_chromaResampled,sx>>1,sy>>1,0,sy);
630
// Return the index in the sub table of the sub matching the time
632
uint32_t ADMVideoVobSub::lookupSub(uint64_t time)
634
int64_t head,tail, cur;
638
while(i<_vobSubInfo->nbLines-1)
640
head=(int64_t)_vobSubInfo->lines[i].startTime;
641
tail=(int64_t) _vobSubInfo->lines[i].stopTime;
642
head+=_param->subShift;
643
tail+=_param->subShift;
644
if(head<=cur &&tail>cur)
646
aprintf("Matching for time %llu : sub %lu starting at :%lu (shift %lu)\n",
647
time,i,_vobSubInfo->lines[i].startTime,_param->subShift);
650
if(head>cur) return NOSUB;