예제 #1
0
def GenerateThumbnailBytes( path, target_resolution, mime, duration, num_frames, percentage_in = 35 ):
    
    if mime in ( HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP, HC.IMAGE_TIFF, HC.IMAGE_ICON ): # not apng atm
        
        thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( path, target_resolution, mime )
        
    else:
        
        if mime == HC.APPLICATION_FLASH:
            
            ( os_file_handle, temp_path ) = HydrusPaths.GetTempPath()
            
            try:
                
                HydrusFlashHandling.RenderPageToFile( path, temp_path, 1 )
                
                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( temp_path, target_resolution, mime )
                
            except:
                
                thumb_path = os.path.join( HC.STATIC_DIR, 'flash.png' )
                
                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath( thumb_path, target_resolution, mime )
                
            finally:
                
                HydrusPaths.CleanUpTempPath( os_file_handle, temp_path )
                
            
        else:
            
            renderer = HydrusVideoHandling.VideoRendererFFMPEG( path, mime, duration, num_frames, target_resolution )
            
            renderer.read_frame() # this initialises the renderer and loads the first frame as a fallback
            
            desired_thumb_frame = int( ( percentage_in / 100.0 ) * num_frames )
            
            renderer.set_position( desired_thumb_frame )
            
            numpy_image = renderer.read_frame()
            
            if numpy_image is None:
                
                raise Exception( 'Could not create a thumbnail from that video!' )
                
            
            numpy_image = HydrusImageHandling.ResizeNumPyImage( numpy_image, target_resolution ) # just in case ffmpeg doesn't deliver right
            
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesNumPy( numpy_image, mime )
            
            renderer.Stop()
            
            del renderer
            
        
    
    return thumbnail_bytes
예제 #2
0
def IsPNGAnimated(file_header_bytes):

    apng_actl_bytes = HydrusVideoHandling.GetAPNGACTLChunk(file_header_bytes)

    if apng_actl_bytes is not None:

        # this is an animated png

        # acTL chunk in an animated png is 4 bytes of num frames, then 4 bytes of num times to loop
        # https://wiki.mozilla.org/APNG_Specification#.60acTL.60:_The_Animation_Control_Chunk

        num_frames = HydrusVideoHandling.GetAPNGNumFrames(apng_actl_bytes)

        if num_frames > 1:

            return True

    return False
예제 #3
0
def GetMime(path, ok_to_look_for_hydrus_updates=False):

    size = os.path.getsize(path)

    if size == 0:

        raise HydrusExceptions.ZeroSizeFileException('File is of zero length!')

    if ok_to_look_for_hydrus_updates and size < 64 * 1024 * 1024:

        with open(path, 'rb') as f:

            update_network_bytes = f.read()

        try:

            update = HydrusSerialisable.CreateFromNetworkBytes(
                update_network_bytes)

            if isinstance(update, HydrusNetwork.ContentUpdate):

                return HC.APPLICATION_HYDRUS_UPDATE_CONTENT

            elif isinstance(update, HydrusNetwork.DefinitionsUpdate):

                return HC.APPLICATION_HYDRUS_UPDATE_DEFINITIONS

        except:

            pass

    with open(path, 'rb') as f:

        bit_to_check = f.read(256)

    for (offsets_and_headers, mime) in headers_and_mime:

        it_passes = False not in (bit_to_check[offset:].startswith(header)
                                  for (offset, header) in offsets_and_headers)

        if it_passes:

            if mime in (HC.UNDETERMINED_WM, HC.UNDETERMINED_MP4):

                return HydrusVideoHandling.GetMime(path)

            elif mime == HC.UNDETERMINED_PNG:

                if IsPNGAnimated(bit_to_check):

                    return HC.IMAGE_APNG

                else:

                    return HC.IMAGE_PNG

            else:

                return mime

    if HydrusText.LooksLikeHTML(bit_to_check):

        return HC.TEXT_HTML

    # it is important this goes at the end, because ffmpeg has a billion false positives!
    # for instance, it once thought some hydrus update files were mpegs
    try:

        mime = HydrusVideoHandling.GetMime(path)

        if mime != HC.APPLICATION_UNKNOWN:

            return mime

    except HydrusExceptions.UnsupportedFileException:

        pass

    except Exception as e:

        HydrusData.Print('FFMPEG had trouble with: ' + path)
        HydrusData.PrintException(e, do_wait=False)

    return HC.APPLICATION_UNKNOWN
예제 #4
0
def GetFileInfo(path, mime=None, ok_to_look_for_hydrus_updates=False):

    size = os.path.getsize(path)

    if size == 0:

        raise HydrusExceptions.ZeroSizeFileException('File is of zero length!')

    if mime is None:

        mime = GetMime(
            path, ok_to_look_for_hydrus_updates=ok_to_look_for_hydrus_updates)

    if mime not in HC.ALLOWED_MIMES:

        if mime == HC.TEXT_HTML:

            raise HydrusExceptions.UnsupportedFileException(
                'Looks like HTML -- maybe the client needs to be taught how to parse this?'
            )

        elif mime == HC.APPLICATION_UNKNOWN:

            raise HydrusExceptions.UnsupportedFileException(
                'Unknown filetype!')

        else:

            raise HydrusExceptions.UnsupportedFileException(
                'Filetype is not permitted!')

    width = None
    height = None
    duration = None
    num_frames = None
    num_words = None

    if mime in HC.MIMES_THAT_DEFINITELY_HAVE_AUDIO:

        has_audio = True

    else:

        has_audio = False

    if mime in (HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP,
                HC.IMAGE_TIFF, HC.IMAGE_ICON):

        ((width, height), duration,
         num_frames) = HydrusImageHandling.GetImageProperties(path, mime)

    elif mime == HC.APPLICATION_CLIP:

        ((width, height), duration,
         num_frames) = HydrusClipHandling.GetClipProperties(path)

    elif mime == HC.APPLICATION_FLASH:

        ((width, height), duration,
         num_frames) = HydrusFlashHandling.GetFlashProperties(path)

    elif mime == HC.IMAGE_APNG:

        ((width, height), duration, num_frames,
         has_audio) = HydrusVideoHandling.GetFFMPEGAPNGProperties(path)

    elif mime == HC.APPLICATION_PDF:

        num_words = HydrusDocumentHandling.GetPDFNumWords(
            path)  # this now give None until a better solution can be found

    elif mime == HC.APPLICATION_PSD:

        (width, height) = HydrusImageHandling.GetPSDResolution(path)

    elif mime in HC.VIDEO:

        ((width, height), duration, num_frames,
         has_audio) = HydrusVideoHandling.GetFFMPEGVideoProperties(path)

    elif mime in HC.AUDIO:

        ffmpeg_lines = HydrusVideoHandling.GetFFMPEGInfoLines(path)

        (file_duration_in_s, stream_duration_in_s
         ) = HydrusVideoHandling.ParseFFMPEGDuration(ffmpeg_lines)

        duration = int(file_duration_in_s * 1000)

    if width is not None and width < 0:

        width *= -1

    if height is not None and height < 0:

        width *= -1

    if duration is not None and duration < 0:

        duration *= -1

    if num_frames is not None and num_frames < 0:

        num_frames *= -1

    if num_words is not None and num_words < 0:

        num_words *= -1

    return (size, mime, width, height, duration, num_frames, has_audio,
            num_words)
예제 #5
0
 def THREADRender( self ):
     
     hash = self._media.GetHash()
     mime = self._media.GetMime()
     duration = self._media.GetDuration()
     num_frames_in_video = self._media.GetNumFrames()
     
     client_files_manager = HG.client_controller.client_files_manager
     
     time.sleep( 0.00001 )
     
     if self._media.GetMime() == HC.IMAGE_GIF:
         
         ( self._durations, self._times_to_play_gif ) = HydrusImageHandling.GetGIFFrameDurations( self._path )
         
         self._renderer = ClientVideoHandling.GIFRenderer( self._path, num_frames_in_video, self._target_resolution )
         
     else:
         
         self._renderer = HydrusVideoHandling.VideoRendererFFMPEG( self._path, mime, duration, num_frames_in_video, self._target_resolution )
         
     
     # give ui a chance to draw a blank frame rather than hard-charge right into CPUland
     time.sleep( 0.00001 )
     
     self.GetReadyForFrame( self._init_position )
     
     with self._lock:
         
         self._initialised = True
         
     
     while True:
         
         if self._stop or HG.view_shutdown:
             
             self._renderer.Stop()
             
             self._renderer = None
             
             with self._lock:
                 
                 self._frames = {}
                 
             
             return
             
         
         #
         
         with self._lock:
             
             # lets see if we should move the renderer to a new position
             
             next_render_is_out_of_buffer = FrameIndexOutOfRange( self._next_render_index, self._buffer_start_index, self._buffer_end_index )
             buffer_not_fully_rendered = self._last_index_rendered != self._buffer_end_index
             
             currently_rendering_out_of_buffer = next_render_is_out_of_buffer and buffer_not_fully_rendered
             
             will_render_ideal_frame_soon = self._IndexInRange( self._next_render_index, self._buffer_start_index, self._ideal_next_frame )
             
             need_ideal_next_frame = not self._HasFrame( self._ideal_next_frame )
             
             will_not_get_to_ideal_frame = need_ideal_next_frame and not will_render_ideal_frame_soon
             
             if currently_rendering_out_of_buffer or will_not_get_to_ideal_frame:
                 
                 # we cannot get to the ideal next frame, so we need to rewind/reposition
                 
                 self._renderer.set_position( self._buffer_start_index )
                 
                 self._last_index_rendered = -1
                 
                 self._next_render_index = self._buffer_start_index
                 
             
             #
             
             need_to_render = self._last_index_rendered != self._buffer_end_index
             
         
         if need_to_render:
             
             with self._lock:
                 
                 self._rendered_first_frame = True
                 
                 frame_index = self._next_render_index # keep this before the get call, as it increments in a clock arithmetic way afterwards
                 
                 renderer = self._renderer
                 
             
             try:
                 
                 numpy_image = renderer.read_frame()
                 
             except Exception as e:
                 
                 HydrusData.ShowException( e )
                 
                 return
                 
             finally:
                 
                 with self._lock:
                     
                     self._last_index_rendered = frame_index
                     
                     self._next_render_index = ( self._next_render_index + 1 ) % num_frames_in_video
                     
                 
             
             with self._lock:
                 
                 if self._next_render_index == 0 and self._buffer_end_index != num_frames_in_video - 1:
                     
                     # we need to rewind renderer
                     
                     self._renderer.set_position( 0 )
                     
                     self._last_index_rendered = -1
                     
                 
                 should_save_frame = not self._HasFrame( frame_index )
                 
             
             if should_save_frame:
                 
                 frame = GenerateHydrusBitmapFromNumPyImage( numpy_image, compressed = False )
                 
                 with self._lock:
                     
                     self._frames[ frame_index ] = frame
                     
                     self._MaintainBuffer()
                     
                 
             
             with self._lock:
                 
                 work_still_to_do = self._last_index_rendered != self._buffer_end_index
                 
             
             if work_still_to_do:
                 
                 time.sleep( 0.0001 )
                 
             else:
                 
                 half_a_frame = ( self._average_frame_duration / 1000.0 ) * 0.5
                 
                 sleep_duration = min( 0.1, half_a_frame ) # for 10s-long 3-frame gifs, wew
                 
                 time.sleep( sleep_duration ) # just so we don't spam cpu
                 
             
         else:
             
             self._render_event.wait( 1 )
             
             self._render_event.clear()
예제 #6
0
def GenerateThumbnailBytes(path,
                           target_resolution,
                           mime,
                           duration,
                           num_frames,
                           percentage_in=35):

    if mime in (HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP,
                HC.IMAGE_TIFF, HC.IMAGE_ICON):  # not apng atm

        thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
            path, target_resolution, mime)
    elif mime in [HC.APPLICATION_ZIP]:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            cmd = ["unzip", path, '-d', temp_dir_path]
            subprocess.call(cmd)
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                cover, target_resolution, mime)
        except Exception as e:
            thumb_path = os.path.join(HC.STATIC_DIR, 'zip.png')
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                thumb_path, target_resolution, mime)
    elif mime in [HC.APPLICATION_RAR]:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            cmd = ["unrar", 'x', path, temp_dir_path]
            subprocess.call(cmd)
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                cover, target_resolution, mime)
        except Exception as e:
            thumb_path = os.path.join(HC.STATIC_DIR, 'rar.png')
            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                thumb_path, target_resolution, mime)

    else:

        if mime == HC.APPLICATION_FLASH:

            (os_file_handle, temp_path) = HydrusPaths.GetTempPath()

            try:

                HydrusFlashHandling.RenderPageToFile(path, temp_path, 1)

                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                    temp_path, target_resolution, mime)

            except:

                thumb_path = os.path.join(HC.STATIC_DIR, 'flash.png')

                thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesFromStaticImagePath(
                    thumb_path, target_resolution, mime)

            finally:

                HydrusPaths.CleanUpTempPath(os_file_handle, temp_path)

        else:

            renderer = HydrusVideoHandling.VideoRendererFFMPEG(
                path, mime, duration, num_frames, target_resolution)

            renderer.read_frame(
            )  # this initialises the renderer and loads the first frame as a fallback

            desired_thumb_frame = int((percentage_in / 100.0) * num_frames)

            renderer.set_position(desired_thumb_frame)

            numpy_image = renderer.read_frame()

            if numpy_image is None:

                raise Exception(
                    'Could not create a thumbnail from that video!')

            numpy_image = HydrusImageHandling.ResizeNumPyImage(
                numpy_image,
                target_resolution)  # just in case ffmpeg doesn't deliver right

            thumbnail_bytes = HydrusImageHandling.GenerateThumbnailBytesNumPy(
                numpy_image, mime)

            renderer.Stop()

            del renderer

    return thumbnail_bytes
예제 #7
0
def GetMime(path, ok_to_look_for_hydrus_updates=False):

    size = os.path.getsize(path)

    if size == 0:

        raise HydrusExceptions.FileSizeException('File is of zero length!')

    with open(path, 'rb') as f:

        bit_to_check = f.read(256)

    for (offset, header, mime) in header_and_mime:

        offset_bit_to_check = bit_to_check[offset:]

        if offset_bit_to_check.startswith(header):

            if mime == HC.UNDETERMINED_WM:

                if HydrusVideoHandling.HasVideoStream(path):

                    return HC.VIDEO_WMV

                # we'll catch and verify wma later

            elif mime == HC.UNDETERMINED_PNG:

                if HydrusVideoHandling.HasVideoStream(path):

                    return HC.IMAGE_APNG

                else:

                    return HC.IMAGE_PNG

            else:

                return mime

    try:

        mime = HydrusVideoHandling.GetMime(path)

        if mime != HC.APPLICATION_UNKNOWN:

            return mime

    except HydrusExceptions.UnsupportedFileException:

        pass

    except Exception as e:

        HydrusData.Print('FFMPEG had trouble with: ' + path)
        HydrusData.PrintException(e, do_wait=False)

    if HydrusText.LooksLikeHTML(bit_to_check):

        return HC.TEXT_HTML

    if ok_to_look_for_hydrus_updates:

        with open(path, 'rb') as f:

            update_network_bytes = f.read()

        try:

            update = HydrusSerialisable.CreateFromNetworkBytes(
                update_network_bytes)

            if isinstance(update, HydrusNetwork.ContentUpdate):

                return HC.APPLICATION_HYDRUS_UPDATE_CONTENT

            elif isinstance(update, HydrusNetwork.DefinitionsUpdate):

                return HC.APPLICATION_HYDRUS_UPDATE_DEFINITIONS

        except:

            pass

    return HC.APPLICATION_UNKNOWN
예제 #8
0
def GetFileInfo(path, mime=None, ok_to_look_for_hydrus_updates=False):

    size = os.path.getsize(path)

    if size == 0:

        raise HydrusExceptions.FileSizeException('File is of zero length!')

    if mime is None:

        mime = GetMime(
            path, ok_to_look_for_hydrus_updates=ok_to_look_for_hydrus_updates)

    if mime not in HC.ALLOWED_MIMES:

        if mime == HC.TEXT_HTML:

            raise HydrusExceptions.UnsupportedFileException(
                'Looks like HTML -- maybe the client needs to be taught how to parse this?'
            )

        elif mime == HC.APPLICATION_UNKNOWN:

            raise HydrusExceptions.UnsupportedFileException(
                'Unknown filetype!')

        else:

            raise HydrusExceptions.UnsupportedFileException(
                'Filetype is not permitted!')

    width = None
    height = None
    duration = None
    num_frames = None
    num_words = None

    if mime in (HC.IMAGE_JPEG, HC.IMAGE_PNG, HC.IMAGE_GIF, HC.IMAGE_WEBP,
                HC.IMAGE_TIFF, HC.IMAGE_ICON):
        ((width, height), duration,
         num_frames) = HydrusImageHandling.GetImageProperties(path, mime)
    elif mime == HC.APPLICATION_ZIP:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            subprocess.call(["unzip", path, '-d', temp_dir_path])
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            ((width, height), duration,
             num_frames) = HydrusImageHandling.GetImageProperties(
                 cover, HC.IMAGE_PNG)
            # TODO: delete dir
        except Exception as e:
            (width, height, duration, num_frames) = (300, 300, 0, 0)
    elif mime == HC.APPLICATION_RAR:
        temp_dir_path = HydrusPaths.GetTempDir()
        try:
            subprocess.call(["unrar", path, temp_dir_path])
            cover = sorted(list(Path(temp_dir_path).rglob("*.jpg")) +
                           list(Path(temp_dir_path).rglob("*.png")),
                           key=lambda p: p.name)[0].as_posix()
            ((width, height), duration,
             num_frames) = HydrusImageHandling.GetImageProperties(
                 cover, HC.IMAGE_PNG)
        except Exception as e:
            (width, height, duration, num_frames) = (300, 300, 0, 0)

    elif mime == HC.APPLICATION_FLASH:

        ((width, height), duration,
         num_frames) = HydrusFlashHandling.GetFlashProperties(path)

    elif mime in (HC.IMAGE_APNG, HC.VIDEO_AVI, HC.VIDEO_FLV, HC.VIDEO_WMV,
                  HC.VIDEO_MOV, HC.VIDEO_MP4, HC.VIDEO_MKV, HC.VIDEO_REALMEDIA,
                  HC.VIDEO_WEBM, HC.VIDEO_MPEG):

        ((width, height), duration,
         num_frames) = HydrusVideoHandling.GetFFMPEGVideoProperties(path)

    elif mime == HC.APPLICATION_PDF:

        num_words = HydrusDocumentHandling.GetPDFNumWords(
            path)  # this now give None until a better solution can be found

    elif mime == HC.APPLICATION_PSD:

        (width, height) = HydrusImageHandling.GetPSDResolution(path)

    elif mime in HC.AUDIO:

        ffmpeg_lines = HydrusVideoHandling.GetFFMPEGInfoLines(path)

        (file_duration_in_s, stream_duration_in_s
         ) = HydrusVideoHandling.ParseFFMPEGDuration(ffmpeg_lines)

        duration = int(file_duration_in_s * 1000)

    if mime in HC.MIMES_THAT_DEFINITELY_HAVE_AUDIO:

        has_audio = True

    elif mime in HC.MIMES_THAT_MAY_HAVE_AUDIO:

        has_audio = HydrusAudioHandling.VideoHasAudio(path)

    else:

        has_audio = False

    if width is not None and width < 0:

        width *= -1

    if height is not None and height < 0:

        width *= -1

    if duration is not None and duration < 0:

        duration *= -1

    if num_frames is not None and num_frames < 0:

        num_frames *= -1

    if num_words is not None and num_words < 0:

        num_words *= -1

    return (size, mime, width, height, duration, num_frames, has_audio,
            num_words)
def VideoHasAudio(path):

    info_lines = HydrusVideoHandling.GetFFMPEGInfoLines(path)

    (audio_found, audio_format) = ParseFFMPEGAudio(info_lines)

    if not audio_found:

        return False

    # just because video metadata has an audio stream doesn't mean it has audio. some vids have silent audio streams lmao
    # so, let's read it as PCM and see if there is any noise
    # this obviously only works for single audio stream vids, we'll adapt this if someone discovers a multi-stream mkv with a silent channel that doesn't work here

    cmd = [HydrusVideoHandling.FFMPEG_PATH]

    # this is perhaps not sensible for eventual playback and I should rather go for wav file-like and feed into python 'wave' in order to maintain stereo/mono and so on and have easy chunk-reading

    cmd.extend(['-i', path, '-loglevel', 'quiet', '-f', 's16le', '-'])

    sbp_kwargs = HydrusData.GetSubprocessKWArgs()

    HydrusData.CheckProgramIsNotShuttingDown()

    try:

        process = subprocess.Popen(cmd,
                                   bufsize=65536,
                                   stdin=subprocess.PIPE,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE,
                                   **sbp_kwargs)

    except FileNotFoundError as e:

        HydrusData.ShowText('Cannot render audio--FFMPEG not found!')

        raise

    # silent PCM data is just 00 bytes
    # every now and then, you'll get a couple ffs for some reason, but this is not legit audio data

    try:

        chunk_of_pcm_data = process.stdout.read(65536)

        while len(chunk_of_pcm_data) > 0:

            # iterating over bytes gives you ints, recall
            if True in (b != 0 and b != 255 for b in chunk_of_pcm_data):

                return True

            chunk_of_pcm_data = process.stdout.read(65536)

        return False

    finally:

        process.terminate()

        process.stdout.close()
        process.stderr.close()