mirror of https://github.com/odrling/Aegisub
Added a glitchy pngout optimizer, and added an introduction to the specs
Originally committed to SVN as r267.
This commit is contained in:
parent
99d7233474
commit
8eeb303eb3
|
@ -70,6 +70,7 @@ Please visit http://aegisub.net to download latest version
|
|||
- Removed the "Help" button from Find/Replace dialog. (AMZ)
|
||||
- Added a bias slider to the "make times continuous" function in timing post-processor, which sets the point between the subs where the two lines will meet. (AMZ)
|
||||
- Separated keyframe thresholds on the timing post-processor in start and end. (AMZ)
|
||||
- Aegisub no longer enjoys littering your temporary files folder with 0 kB files. (AMZ)
|
||||
|
||||
|
||||
= 1.09 beta - 2006.01.16 ===========================
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
// Headers
|
||||
#include <wx/image.h>
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/docview.h>
|
||||
#include "subtitle_format_prs.h"
|
||||
#include "ass_file.h"
|
||||
#include "ass_dialogue.h"
|
||||
|
@ -98,112 +100,36 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
|
|||
catch (AvisynthError &err) {
|
||||
throw _T("AviSynth error: ") + wxString(err.msg,wxConvLocal);
|
||||
}
|
||||
PClip clip1 = script1.AsClip();
|
||||
PClip clip2 = script2.AsClip();
|
||||
|
||||
// Get range
|
||||
std::vector<int> frames = GetFrameRanges();
|
||||
|
||||
// Render all frames that were detected to contain subtitles
|
||||
PClip clip1 = script1.AsClip();
|
||||
PClip clip2 = script2.AsClip();
|
||||
// Set variables
|
||||
int totalFrames = frames.size();
|
||||
int id = 0;
|
||||
PRSDisplay *lastDisplay = NULL;
|
||||
id = 0;
|
||||
lastDisplay = NULL;
|
||||
|
||||
// Render all frames that were detected to contain subtitles
|
||||
for (int framen=0;framen<totalFrames;framen++) {
|
||||
// Render it?
|
||||
// Is this frame supposed to be rendered?
|
||||
if (frames[framen] == 0) continue;
|
||||
|
||||
// Read its image
|
||||
// Read the frame image
|
||||
PVideoFrame frame1 = clip1->GetFrame(framen,env1);
|
||||
PVideoFrame frame2 = clip2->GetFrame(framen,env2);
|
||||
|
||||
// Convert to PNG (the block is there to force it to dealloc bmp earlier)
|
||||
// Prepare to get wxImage
|
||||
int x=0,y=0;
|
||||
int maxalpha=0;
|
||||
int imgw,imgh;
|
||||
wxMemoryOutputStream stream;
|
||||
{
|
||||
// Get wxImage and convert to PNG
|
||||
wxImage bmp = CalculateAlpha(frame1->GetReadPtr(),frame2->GetReadPtr(),frame1->GetRowSize(),frame1->GetHeight(),frame1->GetPitch(),&x,&y,&maxalpha);
|
||||
if (!bmp.Ok()) continue;
|
||||
bmp.SaveFile(stream,wxBITMAP_TYPE_PNG);
|
||||
//bmp.SaveFile(filename + wxString::Format(_T("%i.png"),id),wxBITMAP_TYPE_PNG);
|
||||
|
||||
// Get size
|
||||
imgw = bmp.GetWidth();
|
||||
imgh = bmp.GetHeight();
|
||||
}
|
||||
// Get wxImage
|
||||
wxImage bmp = CalculateAlpha(frame1->GetReadPtr(),frame2->GetReadPtr(),frame1->GetRowSize(),frame1->GetHeight(),frame1->GetPitch(),&x,&y,&maxalpha);
|
||||
if (!bmp.Ok()) continue;
|
||||
|
||||
// Create PRSImage
|
||||
PRSImage *img = new PRSImage;
|
||||
img->id = id;
|
||||
img->imageType = PNG_IMG;
|
||||
img->w = imgw;
|
||||
img->h = imgh;
|
||||
img->maxAlpha = maxalpha;
|
||||
img->dataLen = stream.GetSize();
|
||||
img->data = new char[img->dataLen];
|
||||
stream.CopyTo(img->data,img->dataLen);
|
||||
|
||||
// Hash the PRSImage data
|
||||
md5_state_t state;
|
||||
md5_init(&state);
|
||||
md5_append(&state,(md5_byte_t*)img->data,img->dataLen);
|
||||
md5_finish(&state,(md5_byte_t*)img->md5);
|
||||
|
||||
// Check for duplicates
|
||||
PRSImage *dupe = file.FindDuplicateImage(img);
|
||||
int useID = id;
|
||||
|
||||
// Dupe found, use that instead
|
||||
if (dupe) {
|
||||
useID = dupe->id;
|
||||
delete img;
|
||||
img = NULL;
|
||||
}
|
||||
|
||||
// Frame is all OK, add it to file
|
||||
else {
|
||||
file.AddEntry(img);
|
||||
id++;
|
||||
}
|
||||
|
||||
// Find start and end times
|
||||
int startf = framen;
|
||||
while (++framen<totalFrames && frames[framen] == 1);
|
||||
int endf = --framen;
|
||||
int start = VFR_Output.GetTimeAtFrame(startf,true);
|
||||
int end = VFR_Output.GetTimeAtFrame(endf,false);
|
||||
|
||||
// Set blend data
|
||||
unsigned char alpha = 255;
|
||||
unsigned char blend = 0;
|
||||
|
||||
// Check if it's just an extension of last display
|
||||
if (lastDisplay && lastDisplay->id == useID && lastDisplay->endFrame == startf-1 &&
|
||||
lastDisplay->x == x && lastDisplay->y == y && lastDisplay->alpha == alpha && lastDisplay->blend == blend)
|
||||
{
|
||||
lastDisplay->end = start;
|
||||
lastDisplay->endFrame = startf;
|
||||
}
|
||||
|
||||
// It isn't; needs a new display command
|
||||
else {
|
||||
// Create PRSDisplay
|
||||
PRSDisplay *display = new PRSDisplay;
|
||||
display->start = start;
|
||||
display->end = end;
|
||||
display->startFrame = startf;
|
||||
display->endFrame = endf;
|
||||
display->id = useID;
|
||||
display->x = x;
|
||||
display->y = y;
|
||||
display->alpha = alpha;
|
||||
display->blend = blend;
|
||||
lastDisplay = display;
|
||||
|
||||
// Insert into list
|
||||
file.AddEntry(display);
|
||||
}
|
||||
// Add image to file
|
||||
InsertFrame(file,framen,frames,bmp,x,y,maxalpha);
|
||||
}
|
||||
|
||||
// Save file
|
||||
|
@ -212,6 +138,127 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
|
|||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// Insert frame into file
|
||||
void PRSSubtitleFormat::InsertFrame(PRSFile &file,int &framen,std::vector<int> &frames,wxImage &bmp,int x,int y,int maxalpha) {
|
||||
// Generic data holder
|
||||
//bmp.SaveFile(wxString::Format(_T("test_%i.png"),id),wxBITMAP_TYPE_PNG);
|
||||
bool pngout = true;
|
||||
size_t datasize = 0;
|
||||
char *rawData = NULL;
|
||||
std::vector<char> data;
|
||||
|
||||
// PNGout optimize
|
||||
if (pngout) {
|
||||
// Save temporary PNG
|
||||
wxString tempFile = wxFileName::CreateTempFileName(_T("aegiprs"));
|
||||
wxString tempOut = tempFile + _T("out.png");
|
||||
bmp.SaveFile(tempFile,wxBITMAP_TYPE_PNG);
|
||||
|
||||
// Run PNGcrush on it
|
||||
wxExecute(_T("pngout.exe ") + tempFile + _T(" ") + tempOut + _T(" /f0 /y /v"),wxEXEC_SYNC);
|
||||
|
||||
// Read file back
|
||||
FILE *fp = fopen(tempOut.mb_str(wxConvLocal),"rb");
|
||||
fseek(fp,0,SEEK_END);
|
||||
datasize = ftell(fp);
|
||||
data.resize(datasize);
|
||||
rawData = &data[0];
|
||||
rewind(fp);
|
||||
fread(rawData,1,datasize,fp);
|
||||
fclose(fp);
|
||||
|
||||
// Destroy temporary files
|
||||
wxRemoveFile(tempFile);
|
||||
wxRemoveFile(tempOut);
|
||||
}
|
||||
|
||||
// No optimization (much faster)
|
||||
else {
|
||||
// Convert wxImage to PNG directly
|
||||
wxMemoryOutputStream stream;
|
||||
bmp.SaveFile(stream,wxBITMAP_TYPE_PNG);
|
||||
datasize = stream.GetSize();
|
||||
data.resize(datasize);
|
||||
rawData = &data[0];
|
||||
stream.CopyTo(rawData,datasize);
|
||||
}
|
||||
|
||||
// Find start and end times
|
||||
int startf = framen;
|
||||
int totalFrames = frames.size();
|
||||
while (++framen<totalFrames && frames[framen] == 1);
|
||||
int endf = --framen;
|
||||
int start = VFR_Output.GetTimeAtFrame(startf,true);
|
||||
int end = VFR_Output.GetTimeAtFrame(endf,false);
|
||||
|
||||
// Create PRSImage
|
||||
PRSImage *img = new PRSImage;
|
||||
img->id = id;
|
||||
img->imageType = PNG_IMG;
|
||||
img->w = bmp.GetWidth();
|
||||
img->h = bmp.GetHeight();
|
||||
img->maxAlpha = maxalpha;
|
||||
img->dataLen = datasize;
|
||||
img->data = new char[img->dataLen];
|
||||
memcpy(img->data,rawData,img->dataLen);
|
||||
|
||||
// Hash the PRSImage data
|
||||
md5_state_t state;
|
||||
md5_init(&state);
|
||||
md5_append(&state,(md5_byte_t*)img->data,img->dataLen);
|
||||
md5_finish(&state,(md5_byte_t*)img->md5);
|
||||
|
||||
// Check for duplicates
|
||||
PRSImage *dupe = file.FindDuplicateImage(img);
|
||||
int useID = id;
|
||||
|
||||
// Dupe found, use that instead
|
||||
if (dupe) {
|
||||
useID = dupe->id;
|
||||
delete img;
|
||||
img = NULL;
|
||||
}
|
||||
|
||||
// Frame is all OK, add it to file
|
||||
else {
|
||||
file.AddEntry(img);
|
||||
id++;
|
||||
}
|
||||
|
||||
// Set blend data
|
||||
unsigned char alpha = 255;
|
||||
unsigned char blend = 0;
|
||||
|
||||
// Check if it's just an extension of last display
|
||||
if (lastDisplay && lastDisplay->id == useID && lastDisplay->endFrame == startf-1 &&
|
||||
lastDisplay->x == x && lastDisplay->y == y && lastDisplay->alpha == alpha && lastDisplay->blend == blend)
|
||||
{
|
||||
lastDisplay->end = start;
|
||||
lastDisplay->endFrame = startf;
|
||||
}
|
||||
|
||||
// It isn't; needs a new display command
|
||||
else {
|
||||
// Create PRSDisplay
|
||||
PRSDisplay *display = new PRSDisplay;
|
||||
display->start = start;
|
||||
display->end = end;
|
||||
display->startFrame = startf;
|
||||
display->endFrame = endf;
|
||||
display->id = useID;
|
||||
display->x = x;
|
||||
display->y = y;
|
||||
display->alpha = alpha;
|
||||
display->blend = blend;
|
||||
lastDisplay = display;
|
||||
|
||||
// Insert into list
|
||||
file.AddEntry(display);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// Get frame ranges
|
||||
std::vector<int> PRSSubtitleFormat::GetFrameRanges() {
|
||||
|
|
|
@ -43,10 +43,21 @@
|
|||
#include <vector>
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class PRSImage;
|
||||
class PRSDisplay;
|
||||
class PRSFile;
|
||||
|
||||
|
||||
//////////////
|
||||
// PRS writer
|
||||
class PRSSubtitleFormat : public SubtitleFormat {
|
||||
private:
|
||||
PRSDisplay *lastDisplay;
|
||||
int id;
|
||||
|
||||
void InsertFrame(PRSFile &file,int &framen,std::vector<int> &frames,wxImage &bmp,int x,int y,int maxalpha);
|
||||
wxImage SubImageWithAlpha(wxImage src,const wxRect &area);
|
||||
wxImage CalculateAlpha(const unsigned char* frame1, const unsigned char* frame2, int w, int h, int pitch, int *x=NULL, int *y=NULL, int *maxalpha=NULL);
|
||||
std::vector<int> GetFrameRanges();
|
||||
|
|
|
@ -905,6 +905,7 @@ void VideoDisplay::OnPlayTimer(wxTimerEvent &event) {
|
|||
wxString VideoDisplay::GetTempWorkFile () {
|
||||
if (tempfile.IsEmpty()) {
|
||||
tempfile = wxFileName::CreateTempFileName(_T("aegisub"));
|
||||
wxRemoveFile(tempfile);
|
||||
tempfile += _T(".ass");
|
||||
}
|
||||
return tempfile;
|
||||
|
|
|
@ -6,6 +6,45 @@ WARNING: THIS FILE IS HEAVILY OUTDATED!!!!!
|
|||
Pre-Rendered Subtitles
|
||||
----------------------
|
||||
|
||||
Specifications by Neils Martin Hansen
|
||||
Modified and commented by Rodrigo Braz Monteiro
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Pre-Rendered Subtitles (PRS) is a compact raster data format for subtitles
|
||||
to be displayed into video files. It is designed to be simple, fast and small.
|
||||
|
||||
Compared to hardsubs, PRS has the following advantages:
|
||||
- Most of the time, it is smaller (hardsubs often require 15 MB in a 24 minutes
|
||||
video clip, whereas PRS often requires as little as 3 MB).
|
||||
- Can be disabled, for the viewers who preffer to watch the original content.
|
||||
- You can have multiple tracks, for multi-language files.
|
||||
- PRS subtitles are easier to replace, making the Quality Control process much
|
||||
faster.
|
||||
|
||||
Compared to softsubs, it has the following advantages:
|
||||
- Decoding is much faster, which allows you to create every sort of advanced
|
||||
effects that can still be displayed in realtime.
|
||||
- Decoding is much simpler, making it possible to port to a wide range of
|
||||
platforms.
|
||||
- It is harder to "steal" the subtitles.
|
||||
- Does not require the shipment of font files, which might be illegal.
|
||||
|
||||
Other advantages of the PRS format are:
|
||||
- It allows effects that are not possible with any current subtitle format,
|
||||
such as different blending modes.
|
||||
- It makes the task of hardsubbing a complex karaoke several times much faster.
|
||||
- It ensures that the encoder will encode the subtitles exactly as the
|
||||
typesetter envisioned them.
|
||||
- It allows conversion of video into subtitles, e.g. effects done in programs
|
||||
such as Adobe After Effects.
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue