(Supposedly) working PRS writer implemented

Originally committed to SVN as r259.
This commit is contained in:
Rodrigo Braz Monteiro 2006-03-30 06:15:58 +00:00
parent 342322cea5
commit 5682ca97b4
10 changed files with 323 additions and 42 deletions

View file

@ -37,6 +37,7 @@
///////////
// Headers
#include <wx/image.h>
#include <wx/mstream.h>
#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
}

View file

@ -40,7 +40,6 @@
///////////
// Headers
#include "subtitle_format.h"
#include "ram_output_stream.h"
//////////////

View file

@ -34,19 +34,70 @@
//
#pragma once
///////////
// Headers
#include <wx/stream.h>
#include <vector>
#include "prs_display.h"
///////////////////////////
// RAM output stream class
class RAMOutputStream : public wxOutputStream {
public:
std::vector<char*> 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);
}

View file

@ -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);
};

View file

@ -37,18 +37,35 @@
#pragma once
///////////
// Headers
#include <stdio.h>
//////////////
// 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);

View file

@ -36,7 +36,11 @@
///////////
// Headers
#include <stdio.h>
#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<PRSEntry*>::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<PRSEntry*>::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) {
}

View file

@ -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);
};

View file

@ -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);
}

View file

@ -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);
};

98
prs/prs_specs.txt Normal file
View file

@ -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.)