def enqueue(func, *args, **kwargs): if get_setting('redis', 'eager'): func(*args, **kwargs) else: q = Queue(connection=redis_conn, name=get_queue_name(), default_timeout=get_setting('redis', 'timeout')) q.enqueue(func, *args, **kwargs)
def convert_video(infile, outfile, codec, quality, original_bitrate, original_width, original_height): if not codec in constants.VIDEO_CODECS.keys(): raise AttributeError("Parameter 'codec' must be in {0}!".format(constants.VIDEO_CODECS.keys)) commands = get_setting('ffmpeg', 'convert_settings', 'commands', codec) if not os.path.exists(os.path.dirname(outfile)): os.makedirs(os.path.dirname(outfile)) tmp_dir = tempfile.mkdtemp() settings = get_setting('ffmpeg', 'convert_settings', quality) for cmd in commands: if quality == 'original': video_bitrate = min(original_bitrate, int(settings.get('video_bitrate').replace('k', ''))) video_max_bitrate = video_bitrate * 2 video_bufsize = video_max_bitrate cmd = cmd.format( ffmpeg=get_setting('ffmpeg', 'binary'), infile=infile, outfile=outfile, video_bitrate="{0}k".format(int(video_bitrate)), video_max_bitrate="{0}k".format(int(video_max_bitrate)), video_bufsize="{0}k".format(int(video_bufsize)), video_size=settings.get('video_size').format( original_width=original_width, original_height=original_height ), ) else: cmd = cmd.format( ffmpeg=get_setting('ffmpeg', 'binary'), infile=infile, outfile=outfile, video_bitrate=settings.get('video_bitrate'), video_max_bitrate=settings.get('video_max_bitrate'), video_bufsize=settings.get('video_bufsize'), video_size=settings.get('video_size'), ) try: subprocess.check_output(cmd.split(), stderr=subprocess.PIPE, cwd=tmp_dir) except AttributeError: # fallback for Python 2.6 subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, cwd=tmp_dir).communicate() shutil.rmtree(tmp_dir, ignore_errors=True) return os.path.exists(outfile)
def _get_image_paths(infile, n): basename, _ = os.path.splitext(os.path.basename(infile)) path_rel = os.path.join(get_setting('screens_to'), "{0}.{1}.jpg".format(basename, n)) path_abs = os.path.join( settings.MEDIA_ROOT, path_rel, ) return path_rel, path_abs
def video_info(infile): cmd = "{ffmpeg} -i {infile} -y -f rawvideo -vframes 1 /dev/null".format( ffmpeg=get_setting('ffmpeg', "binary"), infile=infile, ) try: result = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) except AttributeError: # fallback for Python 2.6 result = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0] except subprocess.CalledProcessError, e: result = str(e.output)
def _get_image_paths(infile, n): basename, _ = os.path.splitext(os.path.basename(infile)) path_rel = os.path.join( get_setting('screens_to'), "{0}.{1}.jpg".format(basename, n) ) path_abs = os.path.join( settings.MEDIA_ROOT, path_rel, ) return path_rel, path_abs
def create_screen_image(infile, outfile, second): cmd = "{ffmpeg} -itsoffset -{second} -i {infile} -y -vcodec mjpeg -vframes 1 -an -f rawvideo {outfile}".format( ffmpeg=get_setting('ffmpeg', "binary"), infile=infile, second=second, outfile=outfile, ) if not os.path.exists(os.path.dirname(outfile)): os.makedirs(os.path.dirname(outfile)) try: subprocess.check_output(cmd.split(), stderr=subprocess.PIPE) except AttributeError: # fallback for Python 2.6 subprocess.Popen(cmd.split(), stdout=subprocess.PIPE).communicate() except subprocess.CalledProcessError, e: print "CalledProcessError:" print e return False
def _get_video_paths(infile, codec): if not codec in constants.VIDEO_CODECS.keys(): raise AttributeError("Parameter 'codec' must be in {0}!".format(constants.VIDEO_CODECS.keys)) ext = constants.VIDEO_CODECS.get(codec) basename, _ = os.path.splitext(os.path.basename(infile)) paths = {} for quality in constants.VIDEO_QUALITIES + ('original',): rel = os.path.join( get_setting('convert_to'), "{0}.{1}.{2}.{3}".format(basename, codec, quality, ext) ) paths[quality] = { 'relative': rel, 'absolute': os.path.join( settings.MEDIA_ROOT, rel, ), } return paths
def _get_video_paths(infile, codec): if not codec in constants.VIDEO_CODECS.keys(): raise AttributeError("Parameter 'codec' must be in {0}!".format( constants.VIDEO_CODECS.keys)) ext = constants.VIDEO_CODECS.get(codec) basename, _ = os.path.splitext(os.path.basename(infile)) paths = {} for quality in constants.VIDEO_QUALITIES + ('original', ): rel = os.path.join( get_setting('convert_to'), "{0}.{1}.{2}.{3}".format(basename, codec, quality, ext)) paths[quality] = { 'relative': rel, 'absolute': os.path.join( settings.MEDIA_ROOT, rel, ), } return paths
class ConvertedVideo(models.Model): owner = models.ForeignKey(User, null=True, blank=True) video = models.FileField(upload_to=get_setting('convert_to')) original = models.ForeignKey('WebVideo', related_name='converted') codec = models.CharField(max_length=20, choices=constants.VIDEO_CODEC_CHOICES) quality = models.CharField(max_length=20, choices=constants.VIDEO_QUALITY_CHOICES) filesize = models.IntegerField(default=0) duration = models.FloatField(default=0.0, verbose_name=_(u"Duration in seconds")) width = models.IntegerField(default=0) height = models.IntegerField(default=0) bitrate = models.FloatField(default=0.0, verbose_name=_(u"Bitrate in kb/s")) framerate = models.FloatField(default=29.92) status = models.SmallIntegerField(choices=constants.VIDEO_STATE_CHOICES, default=constants.VIDEO_STATE_PENDING, editable=False) def save(self, force_insert=False, force_update=False, using=None, update_fields=None): self.owner = self.original.owner super(ConvertedVideo, self).save(force_insert, force_update, using, update_fields) class Meta: unique_together = ( 'original', 'codec', 'quality', ) def __unicode__(self): return "{0} ({1}, {2})".format(self.video, self.codec, self.quality)
class VideoScreen(models.Model): owner = models.ForeignKey(User, null=True, blank=True) video = models.ForeignKey('WebVideo', related_name='screen') image = models.ImageField(upload_to=get_setting('screens_to')) num = models.IntegerField(max_length=2) def save(self, force_insert=False, force_update=False, using=None, update_fields=None): self.owner = self.video.owner super(VideoScreen, self).save(force_insert, force_update, using, update_fields) class Meta: unique_together = ( 'video', 'num', ) def __unicode__(self): return "{0}, Screen {1}".format(self.video.video, self.num)
'height', 'bitrate', 'framerate', ) readonly_fields = ( 'admin_video', 'original', 'admin_filesize', 'codec', 'quality', 'duration', 'width', 'height', 'bitrate', 'framerate', ) list_filter = ('codec', 'quality') admin_thumb = admin_thumb_helper_video(width=50, height=30) admin_video = admin_video_helper() admin_filesize = admin_filesize_helper() def has_add_permission(self, request): return False if get_setting('use_admin'): admin.site.register(WebVideo, WebVideoAdmin) admin.site.register(VideoScreen, VideoScreenAdmin) admin.site.register(ConvertedVideo, ConvertedVideoAdmin)
# coding=utf-8 from django_webvideo.settings import get_setting, get_queue_name from rq import Queue from redis import Redis redis_conn = Redis( host=get_setting('redis', 'connection', 'host'), db=get_setting('redis', 'connection', 'db'), port=get_setting('redis', 'connection', 'port'), ) def enqueue(func, *args, **kwargs): if get_setting('redis', 'eager'): func(*args, **kwargs) else: q = Queue(connection=redis_conn, name=get_queue_name(), default_timeout=get_setting('redis', 'timeout')) q.enqueue(func, *args, **kwargs)
class WebVideo(models.Model): owner = models.ForeignKey(User, null=True, blank=True, editable=False) video = models.FileField(upload_to=get_setting('upload_to')) filesize = models.IntegerField(default=0, editable=False) duration = models.FloatField(default=0.0, verbose_name=_(u"Duration in seconds"), editable=False) width = models.IntegerField(default=0, editable=False) height = models.IntegerField(default=0, editable=False) bitrate = models.FloatField(default=0.0, verbose_name=_(u"Bitrate in kb/s"), editable=False) framerate = models.FloatField(default=29.92, editable=False) codecs = models.CharField(max_length=255, blank=True, null=True, editable=True) qualities = models.CharField(max_length=255, blank=True, null=True, editable=True) @property def status(self): if self.converted.all().count() == 0: return constants.VIDEO_STATE_PENDING else: return constants.VIDEO_STATE_SUCCESS def __unicode__(self): return self.video.url def save(self, force_insert=False, force_update=False, using=None, update_fields=None): old_video = None if self.pk is not None: try: old_video = WebVideo.objects.get(pk=self.pk).video except WebVideo.DoesNotExist: pass if old_video != self.video: self.converted.all().delete() self.screen.all().delete() super(WebVideo, self).save(force_insert, force_update, using, update_fields) _set_meta(self) self.create_screen_images() self.convert() super(WebVideo, self).save(force_insert, force_update, using, update_fields) def get_screen(self, num=1): try: return self.screen.get(video=self, num=num) except VideoScreen.DoesNotExist: return None def get_video(self, codec, quality): try: return self.converted.get(original=self, codec=codec, quality=quality) except ConvertedVideo.DoesNotExist: return None def convert(self): if self.status != constants.VIDEO_STATE_PENDING: return for codec in self.codecs.split(','): for quality in self.qualities.split(','): #minrate = constants.VIDEO_QUALITY_MIN_BITRATES[quality] #if self.bitrate > 0 and self.bitrate >= minrate: queue.enqueue(_convert_single, self.pk, codec, quality) #queue.enqueue(_convert_single, self.pk, codec, 'original') def convert_single(self, codec, quality): paths = _get_video_paths(self.video.path, codec)[quality] conv = ConvertedVideo(original=self, codec=codec, quality=quality, owner=self.owner) if convert_video(self.video.path, paths.get('absolute'), codec, quality, self.bitrate, self.width, self.height): # get object from db to prevent "no-save" bug in rq conv.video.name = paths.get('relative') conv.status = constants.VIDEO_STATE_SUCCESS _set_meta(conv) conv.save() return True else: conv.status = constants.VIDEO_STATE_ERROR conv.save() return False def create_screen_images(self): if self.duration == 0: return dur = self.duration for num in range(1, constants.NUM_SCREENS + 1): relative, absolute = _get_image_paths(self.video.path, num) if num == 1: frame = round(min(dur * 0.5, 0.5), 2) else: frame = round(dur / constants.NUM_SCREENS * (num * 0.9), 2) if create_screen_image(self.video.path, absolute, frame): VideoScreen(video=self, image=relative, num=num, owner=self.owner).save() def converted_list_admin(self): return [ "{0}, {1}".format(c.codec, c.quality) for c in self.converted.all() ] converted_list_admin.short_description = _('Converted variants')