From 5682ca97b42a0d711d211e4516cdda6aa38a55a6 Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Thu, 30 Mar 2006 06:15:58 +0000 Subject: [PATCH] (Supposedly) working PRS writer implemented Originally committed to SVN as r259. --- core/subtitle_format_prs.cpp | 12 ++- core/subtitle_format_prs.h | 1 - .../prs_display.cpp | 75 +++++++++++--- prs/prs_display.h | 24 +++-- prs/prs_entry.h | 19 +++- prs/prs_file.cpp | 57 ++++++++++- prs/prs_file.h | 4 +- .../prs_image.cpp | 54 ++++++++-- prs/prs_image.h | 21 +++- prs/prs_specs.txt | 98 +++++++++++++++++++ 10 files changed, 323 insertions(+), 42 deletions(-) rename core/ram_output_stream.h => prs/prs_display.cpp (64%) rename core/ram_output_stream.cpp => prs/prs_image.cpp (71%) create mode 100644 prs/prs_specs.txt diff --git a/core/subtitle_format_prs.cpp b/core/subtitle_format_prs.cpp index 2d249388e..a64e3b956 100644 --- a/core/subtitle_format_prs.cpp +++ b/core/subtitle_format_prs.cpp @@ -37,6 +37,7 @@ /////////// // Headers #include +#include #include "subtitle_format_prs.h" #include "ass_file.h" #include "ass_dialogue.h" @@ -114,16 +115,17 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) { // Convert to PNG int x=0,y=0; wxImage bmp = CalculateAlpha(frame1->GetReadPtr(),frame2->GetReadPtr(),frame1->GetRowSize(),frame1->GetHeight(),frame1->GetPitch(),&x,&y); - //bmp.SaveFile(filename + wxString::Format(_T("%i.png"),id),wxBITMAP_TYPE_PNG); - RAMOutputStream stream; + //RAMOutputStream stream; + wxMemoryOutputStream stream; bmp.SaveFile(stream,wxBITMAP_TYPE_PNG); + //bmp.SaveFile(filename + wxString::Format(_T("%i.png"),id),wxBITMAP_TYPE_PNG); // Create PRSImage PRSImage *img = new PRSImage; img->id = id; - img->dataLen = stream.data.size(); + img->dataLen = stream.GetSize(); img->data = new char[img->dataLen]; - memcpy(img->data,&stream.data[0],img->dataLen); + stream.CopyTo(img->data,img->dataLen); // Create PRSDisplay PRSDisplay *display = new PRSDisplay; @@ -143,7 +145,7 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) { } // Save file - file.Save(filename.mb_str(wxConvLocal)); + file.Save((const char*)filename.mb_str(wxConvLocal)); #endif } diff --git a/core/subtitle_format_prs.h b/core/subtitle_format_prs.h index 478e3c385..f35258da7 100644 --- a/core/subtitle_format_prs.h +++ b/core/subtitle_format_prs.h @@ -40,7 +40,6 @@ /////////// // Headers #include "subtitle_format.h" -#include "ram_output_stream.h" ////////////// diff --git a/core/ram_output_stream.h b/prs/prs_display.cpp similarity index 64% rename from core/ram_output_stream.h rename to prs/prs_display.cpp index 28e5fb5cf..84e44d78e 100644 --- a/core/ram_output_stream.h +++ b/prs/prs_display.cpp @@ -34,19 +34,70 @@ // -#pragma once - - /////////// // Headers -#include -#include +#include "prs_display.h" -/////////////////////////// -// RAM output stream class -class RAMOutputStream : public wxOutputStream { -public: - std::vector data; - wxOutputStream& Write(const void *buffer, size_t size); -}; +/////////////// +// Constructor +PRSDisplay::PRSDisplay() { + start = -1; + end = -1; + id = -1; + layer = 0; + x = 0; + y = 0; + alpha = 255; + blend = BLEND_NORMAL; +} + + +////////////// +// Destructor +PRSDisplay::~PRSDisplay() { +} + + +////////////// +// Write data +void PRSDisplay::WriteData(FILE *fp) { + // Write block identifier + fwrite("DSP",1,4,fp); + + // Write block length + unsigned __int32 utemp = 4 + 4 + 4 + 2 + 2 + 2 + 1 + 1; + fwrite(&utemp,4,1,fp); + + // Write start time + utemp = start; + fwrite(&utemp,4,1,fp); + + // Write end time + utemp = end; + fwrite(&utemp,4,1,fp); + + // Write image identifier + utemp = id; + fwrite(&utemp,4,1,fp); + + // Write layer + __int16 shorttemp = layer; + fwrite(&shorttemp,2,1,fp); + + // Write x + shorttemp = x; + fwrite(&shorttemp,2,1,fp); + + // Write y + shorttemp = y; + fwrite(&shorttemp,2,1,fp); + + // Write alpha multiplier + unsigned __int8 chartemp = alpha; + fwrite(&chartemp,1,1,fp); + + // Write blend mode + chartemp = blend; + fwrite(&chartemp,1,1,fp); +} diff --git a/prs/prs_display.h b/prs/prs_display.h index fde46279d..f68112601 100644 --- a/prs/prs_display.h +++ b/prs/prs_display.h @@ -40,11 +40,11 @@ /////////////// // Blend modes enum PRSBlendMode { - NORMAL = 0, - ADD, - SUBTRACT, - INVERSE_SUBTRACT, - MULTIPLY + BLEND_NORMAL = 0, + BLEND_ADD, + BLEND_SUBTRACT, + BLEND_INVERSE_SUBTRACT, + BLEND_MULTIPLY }; @@ -57,11 +57,17 @@ enum PRSBlendMode { // Display class class PRSDisplay : public PRSEntry { public: - int start; // First time to show this on (INCLUSIVE) (possible first frame?) - int end; // Last time to show this on (EXCLUSIVE) (possible last frame?) - int id; // ID of picture to be shown - int layer; // Number of layer to draw this on + unsigned int start; // First time to show this on (INCLUSIVE) (possible first frame?) + unsigned int end; // Last time to show this on (EXCLUSIVE) (possible last frame?) + unsigned int id; // ID of picture to be shown + unsigned int layer; // Number of layer to draw this on short x,y; // X and Y coordinates to draw picture on unsigned char alpha; // Alpha blend of picture unsigned char blend; // Blend mode to use + + PRSDisplay(); + ~PRSDisplay(); + + PRSEntryType GetType() { return DISPLAY_ENTRY; } + void WriteData(FILE *fp); }; diff --git a/prs/prs_entry.h b/prs/prs_entry.h index 063f3f647..974d224f2 100644 --- a/prs/prs_entry.h +++ b/prs/prs_entry.h @@ -37,18 +37,35 @@ #pragma once +/////////// +// Headers +#include + + ////////////// // Prototypes class PRSDisplay; class PRSImage; +/////////////// +// Entry types +enum PRSEntryType { + BASE_ENTRY = 0, + IMAGE_ENTRY, + DISPLAY_ENTRY +}; + + //////////////////////// // PRS Entry base class class PRSEntry { public: PRSEntry() {} - ~PRSEntry() {} + virtual ~PRSEntry() {} + + virtual PRSEntryType GetType() { return BASE_ENTRY; } + virtual void WriteData(FILE *fp) { } static PRSImage* GetImage(PRSEntry* entry); static PRSDisplay* GetDisplay(PRSDisplay* entry); diff --git a/prs/prs_file.cpp b/prs/prs_file.cpp index 4192f312f..d179f4059 100644 --- a/prs/prs_file.cpp +++ b/prs/prs_file.cpp @@ -36,7 +36,11 @@ /////////// // Headers +#include #include "prs_file.h" +#include "prs_entry.h" +#include "prs_image.h" +#include "prs_display.h" /////////////// @@ -48,18 +52,67 @@ PRSFile::PRSFile () { ////////////// // Destructor PRSFile::~PRSFile() { + Reset(); +} + + +////////////// +// Reset file +void PRSFile::Reset() { + // Clear list of entries + std::list::iterator cur; + for (cur=entryList.begin();cur!=entryList.end();cur++) { + delete *cur; + } + entryList.clear(); } //////// // Save -void PRSFile::Save(const char *path) { +void PRSFile::Save(std::string path) { + // I'm using C's stdio instead of C++'s fstream because I feel that fstream is + // pretty lame for binary data, so I need to make sure that no exceptions are thrown from here. + + // TODO: Make this endianness-independent + + // Open file + FILE *fp = fopen(path.c_str(),"wb"); + if (!fp) throw "Failed to open file"; + + try { + // Write the "PRS" (zero-terminated) string ID (4 bytes) + fwrite("PRS",1,4,fp); + + // Write version number (4 bytes) + __int32 temp = 1; + fwrite(&temp,4,1,fp); + + // Write stream name (for future scalability, there is only one for now) + // This is writen as 4 bytes for length, and then length bytes for actual name. + // Since we set length to zero, the actual name string is never writen. + temp = 0; + fwrite(&temp,4,1,fp); + + // Write data blocks + std::list::iterator cur; + for (cur=entryList.begin();cur!=entryList.end();cur++) { + // Data blocks take care of writing themselves + // All of them start with a 4-byte string identifier, and a 4-byte length identifier + // A decoder can (and should!) ignore any block that it doesn't recognize + (*cur)->WriteData(fp); + } + } + catch (...) {} + + // Close file + fclose(fp); } //////// // Load -void PRSFile::Load(const char *path, bool reset) { +void PRSFile::Load(std::string path, bool reset) { } diff --git a/prs/prs_file.h b/prs/prs_file.h index 5087668de..f1d05f216 100644 --- a/prs/prs_file.h +++ b/prs/prs_file.h @@ -60,6 +60,6 @@ public: void AddEntry(PRSEntry *entry); - void Save(const char *path); - void Load(const char *path,bool reset=true); + void Save(std::string path); + void Load(std::string path,bool reset=true); }; diff --git a/core/ram_output_stream.cpp b/prs/prs_image.cpp similarity index 71% rename from core/ram_output_stream.cpp rename to prs/prs_image.cpp index 90d893f85..0b1fe48ce 100644 --- a/core/ram_output_stream.cpp +++ b/prs/prs_image.cpp @@ -36,14 +36,52 @@ /////////// // Headers -#include "ram_output_stream.h" +#include "prs_image.h" -///////// -// Write -wxOutputStream& RAMOutputStream::Write(const void *buffer, size_t size) { - size_t start = data.size(); - data.resize(start+size); - memcpy(&data[start],buffer,size); - return *this; +/////////////// +// Constructor +PRSImage::PRSImage() { + id = -1; + imageType = NULL_IMG; + dataLen = 0; + data = 0; +} + + +////////////// +// Destructor +PRSImage::~PRSImage() { + if (data) { + delete [] data; + data = 0; + dataLen = 0; + } +} + + +////////////// +// Write data +void PRSImage::WriteData(FILE *fp) { + // Write block identifier + fwrite("IMG",1,4,fp); + + // Write block length + unsigned __int32 utemp = 4 + 4 + 4 + dataLen; + fwrite(&utemp,4,1,fp); + + // Write image identifier + utemp = id; + fwrite(&utemp,4,1,fp); + + // Write image format + utemp = imageType; + fwrite(&utemp,4,1,fp); + + // Write data length + utemp = dataLen; + fwrite(&utemp,4,1,fp); + + // Write data + fwrite(data,1,dataLen,fp); } diff --git a/prs/prs_image.h b/prs/prs_image.h index 56ca812c7..1aafce9d9 100644 --- a/prs/prs_image.h +++ b/prs/prs_image.h @@ -42,11 +42,28 @@ #include "prs_entry.h" +/////////////// +// Image types +enum PRSImageType { + WXIMAGE = -1, + NULL_IMG, + PNG_IMG, + BMP_RGB24_IMG +}; + + /////////////// // Image class class PRSImage : public PRSEntry { public: - int id; - int dataLen; + PRSImageType imageType; + unsigned int id; + unsigned int dataLen; void *data; + + PRSImage(); + ~PRSImage(); + + PRSEntryType GetType() { return IMAGE_ENTRY; } + void WriteData(FILE *fp); }; diff --git a/prs/prs_specs.txt b/prs/prs_specs.txt new file mode 100644 index 000000000..07a78b39f --- /dev/null +++ b/prs/prs_specs.txt @@ -0,0 +1,98 @@ + + +WARNING: THIS FILE IS HEAVILY OUTDATED!!!!! + + +Pre-Rendered Subtitles +---------------------- + +PRS stores either full PNG images, partial PNG images (through a number of +blocks) or instructions to do simple modifications (translation, clearing) +to the current output. + +PRS only uses 32 bit RGBA images. + +The data format is binary, designed for integration into containers such as +Matroska. + +PRS subtitle files can be generated by specialised software (rendering directly +to a PRS file or other container supporting PRS) or by a commandline program +taking a PRS definition file and a number of PNG images as input. +The PRS definition file is a text file describing the images to be displayed. + +PRS subtitles are frame-based, that is, a PRS subtitle picture is linked to one +or more frame-numbers in the video. + +All integers are 32 bit unsigned Little Endian unless otherwise specified. + + +PRS stand-alone file format +--------------------------- + +The file starts with a 32 bit magic number, formed by the ASCII string +"PRS". +The magic is followed by an integer specifying the length in bytes of the +subpicture stream name. The subpicture stream name follows immediately +after the length specifier, and is an UTF-8 encoded freeform string. (It may +contain embedded NUL characters, but this is discouraged. It is encouraged to +terminate the stream name with a NUL character.) + +The header is followed by a number of image deifnitions and display commands. +Image definitions and display commands can be mixed in any way, as long as +no display command refers to an undefined image. +If an image identifier is defined twice, the later definition overrides any +earlier ones. + +0x00 "PRS" (zero-terminated) +0x04 version number (32 bit unsigned) +0x08 stream name size (32 bit unsigned) +0x012 stream name string (this won't be writen if the size is 0) + + +Image Definition IMG + +This defines an image data block. This image definition starts with the 32 bit +magic "IMG". This is followed by an integer image identifier, an integer +image byte size and the image data, encoded in the apropriate format. + +0x00 "IMG" (zero-terminated) +0x04 block length (32 bit unsigned) +0x08 image identifier (32 bit unsigned) +0x0C image format (32 bit unsigned; 1 = PNG, and the only supported format for now) +0x10 image data length (32 bit unsigned) +0x14 image data + + +Display Command DSP + +This controls when and how images are displayed on the video. +Start and end frame numbers are both inclusive. + +0x00 "DSP" (zero-terminated) +0x04 block length (32 bit unsigned) +0x08 start time in miliseconds (32 bit unsigned) +0x0C end time in miliseconds (32 bit unsigned) +0x10 image identifier (32 bit unsigned) +0x1C layer (16 bit signed) +0x14 x position (16 bit signed) +0x18 y position (16 bit signed) +0x1A alpha multiplier (8 bit unsigned) +0x1B blend mode (8 bit unsigned) + +Alpha multiplier: +0x00 is "invisible",0xFF is "fully visible". This value is multiplied onto +the alpha value of each pixel in the image to get the actual alpha value for +that pixel. + +Blend modes: + 0 none (dest*(1-alpha) + src*alpha) + 1 add (dest*(1-alpha) + (src+dest)*alpha) + 2 subtract (dest*(1-alpha) + (src-dest)*alpha) + 3 inverse subtract (dest*(1-alpha) + (dest-src)*alpha) + 4 multiply (dest*(1-alpha) + src*dest*alpha) +Values are clipped before they are multiplied with alpha. + +Layers: +If picture A's layer number is larger than picture B, picture A is displayed +on top of picture B. If two pictures have the same layer number, no order is +defined. (It's recommended to use the ordering of the display commands.)