forked from mia/Aegisub
(Supposedly) working PRS writer implemented
Originally committed to SVN as r259.
This commit is contained in:
parent
342322cea5
commit
5682ca97b4
10 changed files with 323 additions and 42 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
///////////
|
||||
// Headers
|
||||
#include "subtitle_format.h"
|
||||
#include "ram_output_stream.h"
|
||||
|
||||
|
||||
//////////////
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
98
prs/prs_specs.txt
Normal 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.)
|
Loading…
Reference in a new issue