Considerable improvements to PRS encoder, it will now prevent the generation of duplicate lines
Originally committed to SVN as r265.
This commit is contained in:
parent
523f545484
commit
784ed8b82f
9 changed files with 214 additions and 72 deletions
|
@ -98,6 +98,112 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
|
|||
throw _T("AviSynth error: ") + wxString(err.msg,wxConvLocal);
|
||||
}
|
||||
|
||||
// Get range
|
||||
std::vector<int> frames = GetFrameRanges();
|
||||
|
||||
// Render all frames that were detected to contain subtitles
|
||||
PClip clip1 = script1.AsClip();
|
||||
PClip clip2 = script2.AsClip();
|
||||
int totalFrames = frames.size();
|
||||
int id = 0;
|
||||
PRSDisplay *lastDisplay = NULL;
|
||||
for (int framen=0;framen<totalFrames;framen++) {
|
||||
// Render it?
|
||||
if (frames[framen] == 0) continue;
|
||||
|
||||
// Read its 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)
|
||||
int x=0,y=0;
|
||||
wxMemoryOutputStream stream;
|
||||
{
|
||||
wxImage bmp = CalculateAlpha(frame1->GetReadPtr(),frame2->GetReadPtr(),frame1->GetRowSize(),frame1->GetHeight(),frame1->GetPitch(),&x,&y);
|
||||
if (!bmp.Ok()) continue;
|
||||
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.GetSize();
|
||||
img->data = new char[img->dataLen];
|
||||
img->imageType = PNG_IMG;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Save file
|
||||
file.Save((const char*)filename.mb_str(wxConvLocal));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// Get frame ranges
|
||||
std::vector<int> PRSSubtitleFormat::GetFrameRanges() {
|
||||
// Loop through subtitles in file
|
||||
AssFile *ass = AssFile::top;
|
||||
std::vector<int> frames;
|
||||
|
@ -170,65 +276,8 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
|
|||
}
|
||||
}
|
||||
|
||||
// Render all frames that were detected to contain subtitles
|
||||
PClip clip1 = script1.AsClip();
|
||||
PClip clip2 = script2.AsClip();
|
||||
int totalFrames = frames.size();
|
||||
int id = 0;
|
||||
for (int framen=0;framen<totalFrames;framen++) {
|
||||
// Render it?
|
||||
if (frames[framen] == 0) continue;
|
||||
|
||||
// Read its image
|
||||
PVideoFrame frame1 = clip1->GetFrame(framen,env1);
|
||||
PVideoFrame frame2 = clip2->GetFrame(framen,env2);
|
||||
|
||||
// Convert to PNG
|
||||
int x=0,y=0;
|
||||
wxImage bmp = CalculateAlpha(frame1->GetReadPtr(),frame2->GetReadPtr(),frame1->GetRowSize(),frame1->GetHeight(),frame1->GetPitch(),&x,&y);
|
||||
if (!bmp.Ok()) continue;
|
||||
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.GetSize();
|
||||
img->data = new char[img->dataLen];
|
||||
img->imageType = PNG_IMG;
|
||||
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);
|
||||
|
||||
// Find start and end times
|
||||
int start = framen;
|
||||
while (++framen<totalFrames && frames[framen] == 1);
|
||||
int end = framen-1;
|
||||
|
||||
// Create PRSDisplay
|
||||
PRSDisplay *display = new PRSDisplay;
|
||||
display->start = VFR_Output.GetTimeAtFrame(start,true);
|
||||
display->end = VFR_Output.GetTimeAtFrame(end,false);
|
||||
display->id = id;
|
||||
display->x = x;
|
||||
display->y = y;
|
||||
display->alpha = 255;
|
||||
display->blend = 0;
|
||||
|
||||
// Insert into list
|
||||
file.AddEntry(img);
|
||||
file.AddEntry(display);
|
||||
id++;
|
||||
}
|
||||
|
||||
// Save file
|
||||
file.Save((const char*)filename.mb_str(wxConvLocal));
|
||||
#endif
|
||||
// Done
|
||||
return frames;
|
||||
}
|
||||
|
||||
|
||||
|
@ -293,9 +342,7 @@ wxImage PRSSubtitleFormat::CalculateAlpha(const unsigned char* frame1, const uns
|
|||
else if (y > maxy) maxy = y;
|
||||
|
||||
// Calculate colour components
|
||||
int mod;
|
||||
if (a > 8) mod = 0;
|
||||
else mod = 256 >> a;
|
||||
int mod = MAX(0,128/a-1);
|
||||
r = MAX(0,r1-mod)*255 / a;
|
||||
g = MAX(0,g1-mod)*255 / a;
|
||||
b = MAX(0,b1-mod)*255 / a;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
///////////
|
||||
// Headers
|
||||
#include "subtitle_format.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
//////////////
|
||||
|
@ -48,6 +49,7 @@ class PRSSubtitleFormat : public SubtitleFormat {
|
|||
private:
|
||||
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);
|
||||
std::vector<int> GetFrameRanges();
|
||||
|
||||
public:
|
||||
bool CanWriteFile(wxString filename);
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
PRSDisplay::PRSDisplay() {
|
||||
start = -1;
|
||||
end = -1;
|
||||
startFrame = -1;
|
||||
endFrame = -1;
|
||||
id = -1;
|
||||
layer = 0;
|
||||
x = 0;
|
||||
|
|
|
@ -58,13 +58,15 @@ enum PRSBlendMode {
|
|||
// Display class
|
||||
class PRSDisplay : public PRSEntry {
|
||||
public:
|
||||
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
|
||||
unsigned __int32 start; // First time to show this on (INCLUSIVE)
|
||||
unsigned __int32 end; // Last time to show this on (EXCLUSIVE)
|
||||
unsigned __int32 startFrame;// First frame to show this on (INCLUSIVE)
|
||||
unsigned __int32 endFrame; // Last frame to show this on (INCLUSIVE)
|
||||
unsigned __int32 id; // ID of picture to be shown
|
||||
unsigned __int32 layer; // Number of layer to draw this on
|
||||
signed __int16 x,y; // X and Y coordinates to draw picture on
|
||||
unsigned __int8 alpha; // Alpha blend of picture
|
||||
unsigned __int8 blend; // Blend mode to use
|
||||
|
||||
PRSDisplay();
|
||||
~PRSDisplay();
|
||||
|
|
57
prs/prs_entry.cpp
Normal file
57
prs/prs_entry.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Aegisub Group nor the names of its contributors
|
||||
// may be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// AEGISUB
|
||||
//
|
||||
// Website: http://aegisub.cellosoft.com
|
||||
// Contact: mailto:zeratul@cellosoft.com
|
||||
//
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "prs_entry.h"
|
||||
#include "prs_display.h"
|
||||
#include "prs_image.h"
|
||||
|
||||
|
||||
///////////////////
|
||||
// Return as image
|
||||
PRSImage* PRSEntry::GetImage(PRSEntry* entry) {
|
||||
if (entry->GetType() == IMAGE_ENTRY) return ((PRSImage*) entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////
|
||||
// Return as display
|
||||
PRSDisplay* PRSEntry::GetDisplay(PRSEntry* entry) {
|
||||
if (entry->GetType() == DISPLAY_ENTRY) return ((PRSDisplay*) entry);
|
||||
return NULL;
|
||||
}
|
|
@ -69,5 +69,5 @@ public:
|
|||
virtual void WriteData(std::vector<char> &vec) { }
|
||||
|
||||
static PRSImage* GetImage(PRSEntry* entry);
|
||||
static PRSDisplay* GetDisplay(PRSDisplay* entry);
|
||||
static PRSDisplay* GetDisplay(PRSEntry* entry);
|
||||
};
|
||||
|
|
|
@ -209,3 +209,31 @@ void PRSFile::Load(std::string path, bool reset) {
|
|||
void PRSFile::AddEntry(PRSEntry *entry) {
|
||||
entryList.push_back(entry);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Checks if there is any duplicate of this image
|
||||
PRSImage *PRSFile::FindDuplicateImage(PRSImage *img) {
|
||||
// Scan looking for duplicate hashes
|
||||
PRSImage *orig;
|
||||
std::list<PRSEntry*>::iterator cur;
|
||||
for (cur=entryList.begin();cur!=entryList.end();cur++) {
|
||||
orig = PRSEntry::GetImage(*cur);
|
||||
if (orig) {
|
||||
// Compare data lengths
|
||||
if (orig->dataLen == img->dataLen) {
|
||||
// Identical data lengths, compare hashes
|
||||
if (memcmp(orig->md5,img->md5,16) == 0) {
|
||||
// Identical hashes, compare image data to be sure
|
||||
if (memcmp(orig->data,img->data,orig->dataLen) == 0) {
|
||||
// Identical data, return
|
||||
return orig;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No duplicate found
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
//////////////
|
||||
// Prototypes
|
||||
class PRSEntry;
|
||||
class PRSImage;
|
||||
|
||||
|
||||
///////////
|
||||
|
@ -62,4 +63,6 @@ public:
|
|||
|
||||
void Save(std::string path);
|
||||
void Load(std::string path,bool reset=true);
|
||||
|
||||
PRSImage *FindDuplicateImage(PRSImage *img);
|
||||
};
|
||||
|
|
|
@ -58,9 +58,10 @@ enum PRSImageType {
|
|||
class PRSImage : public PRSEntry {
|
||||
public:
|
||||
PRSImageType imageType;
|
||||
unsigned int id;
|
||||
unsigned int dataLen;
|
||||
unsigned __int32 id;
|
||||
unsigned __int32 dataLen;
|
||||
void *data;
|
||||
char md5[16];
|
||||
|
||||
PRSImage();
|
||||
~PRSImage();
|
||||
|
|
Loading…
Reference in a new issue