diff --git a/core/subtitle_format_prs.cpp b/core/subtitle_format_prs.cpp index d65805c74..5f9aa704c 100644 --- a/core/subtitle_format_prs.cpp +++ b/core/subtitle_format_prs.cpp @@ -98,6 +98,112 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) { throw _T("AviSynth error: ") + wxString(err.msg,wxConvLocal); } + // Get range + std::vector 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;framenGetFrame(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 (++framenid == 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 PRSSubtitleFormat::GetFrameRanges() { // Loop through subtitles in file AssFile *ass = AssFile::top; std::vector 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;framenGetFrame(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 (++framenstart = 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; diff --git a/core/subtitle_format_prs.h b/core/subtitle_format_prs.h index f35258da7..122453fc3 100644 --- a/core/subtitle_format_prs.h +++ b/core/subtitle_format_prs.h @@ -40,6 +40,7 @@ /////////// // Headers #include "subtitle_format.h" +#include ////////////// @@ -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 GetFrameRanges(); public: bool CanWriteFile(wxString filename); diff --git a/prs/prs_display.cpp b/prs/prs_display.cpp index cae4726c5..580c73600 100644 --- a/prs/prs_display.cpp +++ b/prs/prs_display.cpp @@ -44,6 +44,8 @@ PRSDisplay::PRSDisplay() { start = -1; end = -1; + startFrame = -1; + endFrame = -1; id = -1; layer = 0; x = 0; diff --git a/prs/prs_display.h b/prs/prs_display.h index 1f30af147..9a47bced0 100644 --- a/prs/prs_display.h +++ b/prs/prs_display.h @@ -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(); diff --git a/prs/prs_entry.cpp b/prs/prs_entry.cpp new file mode 100644 index 000000000..9534788c1 --- /dev/null +++ b/prs/prs_entry.cpp @@ -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; +} diff --git a/prs/prs_entry.h b/prs/prs_entry.h index d9d7ae0d8..82562e3db 100644 --- a/prs/prs_entry.h +++ b/prs/prs_entry.h @@ -69,5 +69,5 @@ public: virtual void WriteData(std::vector &vec) { } static PRSImage* GetImage(PRSEntry* entry); - static PRSDisplay* GetDisplay(PRSDisplay* entry); + static PRSDisplay* GetDisplay(PRSEntry* entry); }; diff --git a/prs/prs_file.cpp b/prs/prs_file.cpp index ad84c36a6..e1579090b 100644 --- a/prs/prs_file.cpp +++ b/prs/prs_file.cpp @@ -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::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; +} diff --git a/prs/prs_file.h b/prs/prs_file.h index f1d05f216..04a9e3d83 100644 --- a/prs/prs_file.h +++ b/prs/prs_file.h @@ -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); }; diff --git a/prs/prs_image.h b/prs/prs_image.h index f14dfc51a..7338f20b6 100644 --- a/prs/prs_image.h +++ b/prs/prs_image.h @@ -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();