~ubuntu-branches/ubuntu/trusty/aegisub/trusty

« back to all changes in this revision

Viewing changes to src/subtitle_format_dvd.cpp

  • Committer: Package Import Robot
  • Author(s): Sebastian Reichel
  • Date: 2012-03-16 22:58:00 UTC
  • Revision ID: package-import@ubuntu.com-20120316225800-yfb8h9e5n04rk46a
Tags: upstream-2.1.9
ImportĀ upstreamĀ versionĀ 2.1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) 2008, Rodrigo Braz Monteiro
 
2
// All rights reserved.
 
3
//
 
4
// Redistribution and use in source and binary forms, with or without
 
5
// modification, are permitted provided that the following conditions are met:
 
6
//
 
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.
 
15
//
 
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.
 
27
//
 
28
// -----------------------------------------------------------------------------
 
29
//
 
30
// AEGISUB
 
31
//
 
32
// Website: http://aegisub.cellosoft.com
 
33
// Contact: mailto:zeratul@cellosoft.com
 
34
//
 
35
 
 
36
 
 
37
///////////
 
38
// Headers
 
39
#include "config.h"
 
40
 
 
41
#include "subtitle_format_dvd.h"
 
42
#include "video_provider_dummy.h"
 
43
#include "subtitles_provider_manager.h"
 
44
#include "ass_dialogue.h"
 
45
#include "ass_file.h"
 
46
#undef _OPENMP
 
47
#ifdef _OPENMP
 
48
#include <omp.h>
 
49
#endif
 
50
#include <wx/file.h>
 
51
 
 
52
//#undef MAX_PATH
 
53
//#include <tessdll.h>
 
54
//
 
55
//#pragma comment(lib, "tessdll.lib")
 
56
 
 
57
 
 
58
///////////////
 
59
// Format name
 
60
wxString DVDSubtitleFormat::GetName() {
 
61
        return _T("DVD Subpictures");
 
62
}
 
63
 
 
64
 
 
65
//////////////
 
66
// Extensions
 
67
wxArrayString DVDSubtitleFormat::GetWriteWildcards() {
 
68
        wxArrayString results;
 
69
        results.Add(_T("sup"));
 
70
        return results;
 
71
}
 
72
 
 
73
 
 
74
/////////////
 
75
// Can write
 
76
bool DVDSubtitleFormat::CanWriteFile(wxString filename) {
 
77
        return (filename.Lower().EndsWith(_T(".sup")));
 
78
}
 
79
 
 
80
 
 
81
///////////////////////
 
82
// Get subpicture list
 
83
void DVDSubtitleFormat::GetSubPictureList(std::vector<SubPicture> &pics) {
 
84
        // Create video frame
 
85
        int w = 720;
 
86
        int h = 480;
 
87
        VideoProvider *video = new DummyVideoProvider(10,1,w,h,wxColour(255,0,0),false);
 
88
        AegiVideoFrame srcFrame = video->GetFrame(0);
 
89
        delete video;
 
90
 
 
91
        // Count and index lines
 
92
        using std::list;
 
93
        int count = 0;
 
94
        std::vector<AssDialogue*> diags;
 
95
        for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
 
96
                AssDialogue *current = AssEntry::GetAsDialogue(*cur);
 
97
                if (current) {
 
98
                        diags.push_back(current);
 
99
                        count++;
 
100
                }
 
101
        }
 
102
        pics.resize(count);
 
103
 
 
104
        SubtitlesProvider *provider = NULL;
 
105
        provider = SubtitlesProviderFactoryManager::GetProvider();
 
106
        provider->LoadSubtitles(GetAssFile());
 
107
        //TessDllAPI tess;
 
108
 
 
109
        // Write lines
 
110
        int i=0;
 
111
#ifdef _OPENMP
 
112
        #pragma omp parallel for shared(diags,pics,provider) private(i)
 
113
#endif
 
114
        for (i=0;i<count;i++) {
 
115
                // Dialogue
 
116
                AssDialogue *current = diags[i];
 
117
 
 
118
                // Get the image
 
119
                AegiVideoFrame dst;
 
120
                dst.CopyFrom(srcFrame);
 
121
                double time = (current->Start.GetMS()/1000.0 + current->End.GetMS()/1000.0)/2.0;
 
122
#ifdef _OPENMP
 
123
                #pragma omp critical
 
124
#endif
 
125
                {
 
126
                        provider->DrawSubtitles(dst,time);
 
127
                }
 
128
                wxImage img = dst.GetImage();
 
129
                img.SaveFile(_T("test.bmp"));
 
130
                dst.Clear();
 
131
 
 
132
                // Tesseract test
 
133
                /*
 
134
                tess.BeginPageUpright(img.GetWidth(),img.GetHeight(),img.GetData(),24);
 
135
                ETEXT_DESC *output = tess.Recognize_all_Words();
 
136
                wxString blah;
 
137
                int j;
 
138
                for (int cur = 0; cur < output->count; cur = j) {
 
139
                        const EANYCODE_CHAR* ch = &output->text[cur];
 
140
                        unsigned char unistr[8];
 
141
 
 
142
                        for (int b = 0; b < ch->blanks; ++b) blah += _T(" ");
 
143
 
 
144
                        for (j = cur; j < output->count; j++)   {
 
145
                                const EANYCODE_CHAR* unich = &output->text[j];
 
146
 
 
147
                                if (ch->left != unich->left || ch->right != unich->right ||
 
148
                                        ch->top != unich->top || ch->bottom != unich->bottom)
 
149
                                        break;
 
150
                                unistr[j - cur] = static_cast<unsigned char>(unich->char_code);
 
151
                        }
 
152
                        unistr[j - cur] = '\0';
 
153
                        blah += wxString((char*)unistr,wxConvUTF8);
 
154
                        if (ch->formatting & 64) blah += _T("\n");
 
155
                }
 
156
                wxLogMessage(blah);
 
157
                */
 
158
 
 
159
                // Perform colour reduction on image
 
160
                unsigned char r,g,b;
 
161
                unsigned char *data = img.GetData();
 
162
                const unsigned char *dataRead = data;
 
163
                unsigned char *dataWrite = data;
 
164
                int startY = 0;
 
165
                int endY = 0;
 
166
                int startX = w;
 
167
                int endX = 0;
 
168
 
 
169
                // For each line
 
170
                for (int y=h;--y>=0;) {
 
171
                        bool hasData = false;
 
172
                        int lineStartX = 0;
 
173
                        int lineEndX = 0;
 
174
 
 
175
                        // Scan line
 
176
                        for (int x=w;--x>=0;) {
 
177
                                // Read
 
178
                                r = *(dataRead++);
 
179
                                g = *(dataRead++);
 
180
                                b = *(dataRead++);
 
181
 
 
182
                                // Background
 
183
                                if (r > 127 && g < 20) {
 
184
                                        r = 200;
 
185
                                        g = 0;
 
186
                                        b = 0;
 
187
                                }
 
188
 
 
189
                                // Text
 
190
                                else {
 
191
                                        // Mark coordinates
 
192
                                        hasData = true;
 
193
                                        if (lineStartX == 0) lineStartX = w-x-1;
 
194
                                        lineEndX = w-x-1;
 
195
 
 
196
                                        // Set colour
 
197
                                        if (r > 170 && g > 170) {
 
198
                                                r = 255;
 
199
                                                g = 255;
 
200
                                                b = 255;
 
201
                                        }
 
202
                                        else if (r > 85 && g > 85) {
 
203
                                                r = 127;
 
204
                                                g = 127;
 
205
                                                b = 127;
 
206
                                        }
 
207
                                        else {
 
208
                                                r = 0;
 
209
                                                g = 0;
 
210
                                                b = 0;
 
211
                                        }
 
212
                                }
 
213
 
 
214
                                // Write
 
215
                                *(dataWrite++) = r;
 
216
                                *(dataWrite++) = g;
 
217
                                *(dataWrite++) = b;
 
218
                        }
 
219
 
 
220
                        // Mark as last found so far
 
221
                        if (hasData) {
 
222
                                if (startY == 0) startY = h-y-1;
 
223
                                endY = h-y-1;
 
224
                                if (lineStartX < startX) startX = lineStartX;
 
225
                                if (lineEndX > endX) endX = lineEndX;
 
226
                        }
 
227
                }
 
228
                
 
229
                // Save image data
 
230
                if (startX > endX) endX = startX;
 
231
                if (startY > endY) endY = startY;
 
232
                int sw = endX-startX+1;
 
233
                int sh = endY-startY+1;
 
234
                pics[i].x = startX;
 
235
                pics[i].y = startY;
 
236
                pics[i].w = sw;
 
237
                pics[i].h = sh;
 
238
                pics[i].start = current->Start.GetMS();
 
239
                pics[i].end = current->End.GetMS();
 
240
 
 
241
                // RLE to memory
 
242
                for (int j=0;j<2;j++) {
 
243
                        int curCol = -1;
 
244
                        int col;
 
245
                        int temp;
 
246
                        int len = 0;
 
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);
 
252
 
 
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
 
257
                                        temp = *dataRead;
 
258
                                        if (temp == 200) col = 0;
 
259
                                        else if (temp == 255) col = 1;
 
260
                                        else if (temp == 0) col = 2;
 
261
                                        else col = 3;
 
262
 
 
263
                                        // See if it matches
 
264
                                        if (col == curCol) {
 
265
                                                len++;
 
266
                                                if (len == 255) {
 
267
                                                        groups.push_back(RLEGroup(curCol,len,false));
 
268
                                                        len = 0;
 
269
                                                }
 
270
                                        }
 
271
                                        else {
 
272
                                                if (len) groups.push_back(RLEGroup(curCol,len,false));
 
273
                                                len = 1;
 
274
                                                curCol = col;
 
275
                                        }
 
276
 
 
277
                                        dataRead += 3;
 
278
                                }
 
279
 
 
280
                                // Flush
 
281
                                if (len) groups.push_back(RLEGroup(curCol,0,true));
 
282
                                else {
 
283
                                        groups.back().len = 0;
 
284
                                        groups.back().eol = true;
 
285
                                }
 
286
                                curCol = -1;
 
287
                                len = 0;
 
288
 
 
289
                                // Advance
 
290
                                dataRead += (2*w-sw)*3;
 
291
                                //dataRead += sw*3;
 
292
                        }
 
293
 
 
294
                        // Encode into subpicture format
 
295
                        int nibble[4];
 
296
                        nibble[3] = 0;
 
297
                        bool off = false;
 
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;
 
302
                                int nibbles;
 
303
 
 
304
                                // End of line, write b000000cc
 
305
                                if (groups[m].eol) nibbles = 4;
 
306
 
 
307
                                // Get proper nibble count
 
308
                                else {
 
309
                                        if (len < 4) nibbles = 1;
 
310
                                        else if (len < 16) nibbles = 2;
 
311
                                        else if (len < 64) nibbles = 3;
 
312
                                        else nibbles = 4;
 
313
                                }
 
314
 
 
315
                                // Write nibbles
 
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);
 
322
                                        if (!off) {
 
323
                                                last = nibble[n] << 4;
 
324
                                                data.push_back(last);
 
325
                                        }
 
326
                                        else data.back() = nibble[n] | last;
 
327
                                        off = !off;
 
328
 
 
329
                                        // Check if just wrote end of line
 
330
                                        if (len == 0 && n == 0) {
 
331
                                                last = 0;
 
332
                                                off = false;
 
333
                                        }
 
334
                                }
 
335
                        }
 
336
                        data.resize(data.size());
 
337
                }
 
338
        }
 
339
 
 
340
        // Clean up
 
341
        delete provider;
 
342
        srcFrame.Clear();
 
343
}
 
344
 
 
345
 
 
346
///////////////////////
 
347
// Actually write them
 
348
void DVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
 
349
        // Prepare subtitles
 
350
        CreateCopy();
 
351
        SortLines();
 
352
        StripComments();
 
353
        RecombineOverlaps();
 
354
        MergeIdentical();
 
355
 
 
356
        // Get subpictures
 
357
        std::vector<SubPicture> pics;
 
358
        GetSubPictureList(pics);
 
359
 
 
360
        // Open file for writing
 
361
        wxFile fp(filename,wxFile::write);
 
362
        if (!fp.IsOpened()) throw _T("Could not open file for writing.");
 
363
 
 
364
        // Write each subpicture
 
365
        size_t pos = 0;
 
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);
 
371
                temp = 0;
 
372
                pos += fp.Write(&temp,4);
 
373
 
 
374
                // Calculate lengths
 
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;
 
378
 
 
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);
 
385
 
 
386
                // Write RLE data
 
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());
 
391
 
 
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;
 
403
                int sx = pics[i].x;
 
404
                int sy = pics[i].y;
 
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);
 
413
 
 
414
                // Write control group
 
415
                unsigned char control[] = {
 
416
                        0x00, 0x00,                     // Delay
 
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
 
423
                        0xFF,                           // End block 1
 
424
                        delay_b1, delay_b2,     // Delay
 
425
                        comm2_b1, comm2_b2,     // This command
 
426
                        0x02,                           // Stop display
 
427
                        0xFF                            // End
 
428
                };
 
429
                pos += fp.Write(control,controlLen);
 
430
        }
 
431
}