1
// Copyright (c) 2008, Rodrigo Braz Monteiro
2
// All rights reserved.
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are met:
7
// * Redistributions of source code must retain the above copyright notice,
8
// this list of conditions and the following disclaimer.
9
// * Redistributions in binary form must reproduce the above copyright notice,
10
// this list of conditions and the following disclaimer in the documentation
11
// and/or other materials provided with the distribution.
12
// * Neither the name of the Aegisub Group nor the names of its contributors
13
// may be used to endorse or promote products derived from this software
14
// without specific prior written permission.
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
// POSSIBILITY OF SUCH DAMAGE.
28
// -----------------------------------------------------------------------------
32
// Website: http://aegisub.cellosoft.com
33
// Contact: mailto:zeratul@cellosoft.com
41
#include "subtitle_format_dvd.h"
42
#include "video_provider_dummy.h"
43
#include "subtitles_provider_manager.h"
44
#include "ass_dialogue.h"
53
//#include <tessdll.h>
55
//#pragma comment(lib, "tessdll.lib")
60
wxString DVDSubtitleFormat::GetName() {
61
return _T("DVD Subpictures");
67
wxArrayString DVDSubtitleFormat::GetWriteWildcards() {
68
wxArrayString results;
69
results.Add(_T("sup"));
76
bool DVDSubtitleFormat::CanWriteFile(wxString filename) {
77
return (filename.Lower().EndsWith(_T(".sup")));
81
///////////////////////
82
// Get subpicture list
83
void DVDSubtitleFormat::GetSubPictureList(std::vector<SubPicture> &pics) {
87
VideoProvider *video = new DummyVideoProvider(10,1,w,h,wxColour(255,0,0),false);
88
AegiVideoFrame srcFrame = video->GetFrame(0);
91
// Count and index lines
94
std::vector<AssDialogue*> diags;
95
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
96
AssDialogue *current = AssEntry::GetAsDialogue(*cur);
98
diags.push_back(current);
104
SubtitlesProvider *provider = NULL;
105
provider = SubtitlesProviderFactoryManager::GetProvider();
106
provider->LoadSubtitles(GetAssFile());
112
#pragma omp parallel for shared(diags,pics,provider) private(i)
114
for (i=0;i<count;i++) {
116
AssDialogue *current = diags[i];
120
dst.CopyFrom(srcFrame);
121
double time = (current->Start.GetMS()/1000.0 + current->End.GetMS()/1000.0)/2.0;
126
provider->DrawSubtitles(dst,time);
128
wxImage img = dst.GetImage();
129
img.SaveFile(_T("test.bmp"));
134
tess.BeginPageUpright(img.GetWidth(),img.GetHeight(),img.GetData(),24);
135
ETEXT_DESC *output = tess.Recognize_all_Words();
138
for (int cur = 0; cur < output->count; cur = j) {
139
const EANYCODE_CHAR* ch = &output->text[cur];
140
unsigned char unistr[8];
142
for (int b = 0; b < ch->blanks; ++b) blah += _T(" ");
144
for (j = cur; j < output->count; j++) {
145
const EANYCODE_CHAR* unich = &output->text[j];
147
if (ch->left != unich->left || ch->right != unich->right ||
148
ch->top != unich->top || ch->bottom != unich->bottom)
150
unistr[j - cur] = static_cast<unsigned char>(unich->char_code);
152
unistr[j - cur] = '\0';
153
blah += wxString((char*)unistr,wxConvUTF8);
154
if (ch->formatting & 64) blah += _T("\n");
159
// Perform colour reduction on image
161
unsigned char *data = img.GetData();
162
const unsigned char *dataRead = data;
163
unsigned char *dataWrite = data;
170
for (int y=h;--y>=0;) {
171
bool hasData = false;
176
for (int x=w;--x>=0;) {
183
if (r > 127 && g < 20) {
193
if (lineStartX == 0) lineStartX = w-x-1;
197
if (r > 170 && g > 170) {
202
else if (r > 85 && g > 85) {
220
// Mark as last found so far
222
if (startY == 0) startY = h-y-1;
224
if (lineStartX < startX) startX = lineStartX;
225
if (lineEndX > endX) endX = lineEndX;
230
if (startX > endX) endX = startX;
231
if (startY > endY) endY = startY;
232
int sw = endX-startX+1;
233
int sh = endY-startY+1;
238
pics[i].start = current->Start.GetMS();
239
pics[i].end = current->End.GetMS();
242
for (int j=0;j<2;j++) {
247
//wxImage subPic = img.GetSubImage(wxRect(startX,startY,sw,sh));
248
dataRead = data + ((startY+j)*w+startX)*3;
249
//dataRead = subPic.GetData();
250
std::vector<RLEGroup> groups;
251
groups.reserve(1024);
253
// Read this scanline
254
for (int y=startY+j;y<=endY;y+=2) {
255
for (int x=startX;x<=endX;x++) {
256
// Read current pixel colour
258
if (temp == 200) col = 0;
259
else if (temp == 255) col = 1;
260
else if (temp == 0) col = 2;
267
groups.push_back(RLEGroup(curCol,len,false));
272
if (len) groups.push_back(RLEGroup(curCol,len,false));
281
if (len) groups.push_back(RLEGroup(curCol,0,true));
283
groups.back().len = 0;
284
groups.back().eol = true;
290
dataRead += (2*w-sw)*3;
294
// Encode into subpicture format
298
std::vector<unsigned char> &data = pics[i].data[j];
299
unsigned char last = 0;
300
for (size_t m=0;m<groups.size();m++) {
301
unsigned char len = groups[m].len;
304
// End of line, write b000000cc
305
if (groups[m].eol) nibbles = 4;
307
// Get proper nibble count
309
if (len < 4) nibbles = 1;
310
else if (len < 16) nibbles = 2;
311
else if (len < 64) nibbles = 3;
316
nibble[0] = groups[m].col | ((len & 0x3) << 2);
317
nibble[1] = (len & 0x3C) >> 2;
318
nibble[2] = (len & 0xC0) >> 6;
319
for (int n=nibbles;--n>=0;) {
320
wxASSERT(nibble[n] >= 0 && nibble[n] < 16);
321
wxASSERT(n >= 0 && n < 4);
323
last = nibble[n] << 4;
324
data.push_back(last);
326
else data.back() = nibble[n] | last;
329
// Check if just wrote end of line
330
if (len == 0 && n == 0) {
336
data.resize(data.size());
346
///////////////////////
347
// Actually write them
348
void DVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
357
std::vector<SubPicture> pics;
358
GetSubPictureList(pics);
360
// Open file for writing
361
wxFile fp(filename,wxFile::write);
362
if (!fp.IsOpened()) throw _T("Could not open file for writing.");
364
// Write each subpicture
366
for (size_t i=0;i<pics.size();i++) {
367
// Write sup packet data
368
pos += fp.Write("SP",2);
369
wxUint32 temp = wxUINT32_SWAP_ON_BE(pics[i].start * 90);
370
pos += fp.Write(&temp,4);
372
pos += fp.Write(&temp,4);
375
size_t controlLen = 30;
376
size_t packetLen = 4 + pics[i].data[0].size() + pics[i].data[1].size() + controlLen;
377
size_t packetStart = pos;
379
// Write position of the next packet and control
380
unsigned short temp2;
381
temp2 = wxUINT16_SWAP_ON_LE(packetLen);
382
pos += fp.Write(&temp2,2);
383
temp2 = wxUINT16_SWAP_ON_LE(packetLen-controlLen);
384
pos += fp.Write(&temp2,2);
387
size_t line0pos = pos - packetStart;
388
pos += fp.Write(&pics[i].data[0][0],pics[i].data[0].size());
389
size_t line1pos = pos - packetStart;
390
pos += fp.Write(&pics[i].data[1][0],pics[i].data[1].size());
392
// Control group data
393
size_t comm2add = packetLen - 6;
394
unsigned char comm2_b1 = (comm2add & 0xFF00) >> 8;
395
unsigned char comm2_b2 = comm2add & 0xFF;
396
unsigned char pix0_b1 = (line0pos & 0xFF00) >> 8;
397
unsigned char pix0_b2 = line0pos & 0xFF;
398
unsigned char pix1_b1 = (line1pos & 0xFF00) >> 8;
399
unsigned char pix1_b2 = line1pos & 0xFF;
400
int delay = (pics[i].end - pics[i].start)*90/1024;
401
unsigned char delay_b1 = (delay & 0xFF00) >> 8;
402
unsigned char delay_b2 = delay & 0xFF;
405
int ex = pics[i].w + sx - 1;
406
int ey = pics[i].h + sy - 1;
407
unsigned char dispx_b1 = (sx & 0xFF0) >> 4;
408
unsigned char dispx_b2 = ((sx & 0x0F) << 4) | ((ex & 0xF00) >> 8);
409
unsigned char dispx_b3 = (ex & 0xFF);
410
unsigned char dispy_b1 = (sy & 0xFF0) >> 4;
411
unsigned char dispy_b2 = ((sy & 0x0F) << 4) | ((ey & 0xF00) >> 8);
412
unsigned char dispy_b3 = (ey & 0xFF);
414
// Write control group
415
unsigned char control[] = {
417
comm2_b1, comm2_b2, // Next command
418
0x01, // Start display
419
0x03, 0x82, 0x30, // Set colours
420
0x04, 0xFF, 0xF0, // Alpha blend
421
0x05, dispx_b1, dispx_b2, dispx_b3, dispy_b1, dispy_b2, dispy_b3, // Display area
422
0x06, pix0_b1, pix0_b2, pix1_b1, pix1_b2, // Pixel pointers
424
delay_b1, delay_b2, // Delay
425
comm2_b1, comm2_b2, // This command
426
0x02, // Stop display
429
pos += fp.Write(control,controlLen);