streams per file and no longer per item

This commit is contained in:
j 2011-08-18 14:01:37 +02:00
commit fc26ff01bd
10 changed files with 178 additions and 126 deletions

View file

@ -392,8 +392,9 @@ class Item(models.Model):
def get_stream(self):
stream = {}
if self.streams.all().count():
s = self.streams.all()[0]
videos = self.main_videos()
for video in videos:
s = video.streams.all()[0]
if s.video and s.info:
stream['duration'] = s.info['duration']
if 'video' in s.info and s.info['video']:
@ -404,8 +405,6 @@ class Item(models.Model):
stream['baseUrl'] = '/%s' % self.itemId
else:
stream['baseUrl'] = os.path.dirname(s.video.url)
stream['resolutions'] = sorted(list(set(map(lambda s: int(os.path.splitext(s['profile'])[0][:-1]), self.streams.all().values('profile')))))
stream['formats'] = list(set(map(lambda s: os.path.splitext(s['profile'])[1][1:], self.streams.all().values('profile'))))
return stream
def get_layers(self, user=None):
@ -451,6 +450,11 @@ class Item(models.Model):
if not keys or 'poster' in keys:
i['poster'] = self.get_poster()
videos = self.main_videos()
i['duration'] = sum([v.duration for v in videos])
i['durations'] = [v.duration for v in videos]
i['apsectRatio'] = i.get('aspectratio')
#only needed by admins
if keys and 'posters' in keys:
i['posters'] = self.get_posters()
@ -561,6 +565,7 @@ class Item(models.Model):
'size',
'bitrate',
'numberoffiles',
'parts',
'published',
'modified',
'popularity',
@ -627,12 +632,13 @@ class Item(models.Model):
if len(videos) > 0:
s.duration = sum([v.duration for v in videos])
s.resolution = videos[0].width * videos[0].height
s.aspectratio = int(1000 * utils.parse_decimal(v.display_aspect_ratio))
s.aspectratio = float(utils.parse_decimal(v.display_aspect_ratio))
#FIXME: should be average over all files
if 'bitrate' in videos[0].info:
s.bitrate = videos[0].info['bitrate']
s.pixels = sum([v.pixels for v in videos])
s.numberoffiles = self.files.all().count()
s.parts = len(videos)
s.size = sum([v.size for v in videos]) #FIXME: only size of movies?
s.volume = 0
else:
@ -645,6 +651,7 @@ class Item(models.Model):
s.files = None
s.size = None
s.volume = None
s.parts = 0
if 'color' in self.data:
s.hue, s.saturation, s.lightness = self.data['color']
@ -695,24 +702,34 @@ class Item(models.Model):
'''
Video related functions
'''
def frame(self, position, height=128):
stream = self.streams.filter(profile=settings.VIDEO_PROFILE)
if stream.count()>0:
stream = stream[0]
else:
return None
height = min(height, stream.height())
path = os.path.join(settings.MEDIA_ROOT, self.path(),
'frames', "%dp"%height, "%s.jpg"%position)
if not os.path.exists(path) and stream.video:
extract.frame(stream.video.path, path, position, height)
if not os.path.exists(path):
path = os.path.join(settings.STATIC_ROOT, 'png/frame.broken.png')
return path
offset = 0
videos = self.main_videos()
for video in videos:
if video.duration + offset < position:
offset += video.duration
else:
position = position - offset
stream = video.streams.filter(resolution=settings.VIDEO_RESOLUTIONS[0],
format=settings.VIDEO_FORMATS[0])
if stream.count()>0:
stream = stream[0]
else:
return None
height = min(height, stream.resolution)
path = os.path.join(settings.MEDIA_ROOT, stream.path(),
'frames', "%dp"%height, "%s.jpg"%position)
if not os.path.exists(path) and stream.video:
extract.frame(stream.video.path, path, position, height)
if not os.path.exists(path):
return None
return path
@property
def timeline_prefix(self):
videos = self.main_videos()
if len(videos) == 1:
return os.path.join(settings.MEDIA_ROOT, videos[0].path('timeline'))
return os.path.join(settings.MEDIA_ROOT, self.path(), 'timeline')
def main_videos(self):
@ -890,9 +907,7 @@ class Item(models.Model):
return None
def make_timeline(self):
stream = self.streams.filter(profile=settings.VIDEO_PROFILE)
if stream.count() > 0 and stream[0].video:
extract.timeline(stream[0].video.path, self.timeline_prefix)
print "FIXME, needs to build timeline from parts"
def make_poster(self, force=False):
if not self.poster or force:
@ -1109,53 +1124,6 @@ class Facet(models.Model):
super(Facet, self).save(*args, **kwargs)
class Stream(models.Model):
class Meta:
unique_together = ("item", "profile")
item = models.ForeignKey(Item, related_name='streams')
profile = models.CharField(max_length=255, default='96p.webm')
video = models.FileField(default=None, blank=True, upload_to=lambda f, x: f.path())
source = models.ForeignKey('Stream', related_name='derivatives', default=None, null=True)
available = models.BooleanField(default=False)
info = fields.DictField(default={})
def __unicode__(self):
return u"%s/%s" % (self.item.itemId, self.profile)
def path(self):
return self.item.path(self.profile)
def height(self):
return int(self.profile.split('p')[0])
def extract_derivatives(self):
for profile in settings.VIDEO_DERIVATIVES:
derivative, created = Stream.objects.get_or_create(profile=profile, item=self.item)
if created:
derivative.source = self
derivative.video.name = self.video.name.replace(self.profile, profile)
derivative.encode()
derivative.save()
return True
def encode(self):
if self.source:
video = self.source.video.path
target = self.video.path
profile = self.profile
info = ox.avinfo(video)
if extract.stream(video, target, profile, info):
self.available=True
self.save()
def save(self, *args, **kwargs):
if self.video and not self.info:
self.info = ox.avinfo(self.video.path)
super(Stream, self).save(*args, **kwargs)
class PosterUrl(models.Model):
class Meta:

View file

@ -32,8 +32,12 @@ def update_streams(itemId):
create stream, extract timeline and create derivatives
'''
item = models.Item.objects.get(itemId=itemId)
if item.files.filter(is_main=True, is_video=True, available=False).count() == 0:
item.update_streams()
videos = item.main_videos()
for video in videos:
for f in video.streams.filter(source=None):
f.extract_derivatives()
#if item.files.filter(is_main=True, is_video=True, available=False).count() == 0:
# item.update_streams()
return True
def load_subtitles(itemId):

View file

@ -13,7 +13,7 @@ urlpatterns = patterns("item.views",
(r'^(?P<id>[A-Z0-9].+)/timeline(?P<size>\d+)p\.png$', 'timeline_overview'),
#video
(r'^(?P<id>[A-Z0-9].+)/(?P<profile>\d+p)(?P<index>\d*)\.(?P<format>webm|ogv|mp4)$', 'video'),
(r'^(?P<id>[A-Z0-9].+)/(?P<resolution>\d+)p(?P<index>\d*)\.(?P<format>webm|ogv|mp4)$', 'video'),
#torrent
(r'^(?P<id>[A-Z0-9][A-Za-z0-9]+)/torrent/(?P<filename>.*?)$', 'torrent'),

View file

@ -652,21 +652,25 @@ def torrent(request, id, filename=None):
os.path.basename(filename.encode('utf-8'))
return response
def video(request, id, profile, index=None, format=None):
def video(request, id, resolution, format, index=None):
item = get_object_or_404(models.Item, itemId=id)
if index:
index = int(index) - 1
path = item.main_videos()[index].video.path
#stream = item.streams.filter(profile=profile)[index]
#path = stream.video.path
else:
stream = get_object_or_404(item.streams, profile="%s.%s" % (profile, format))
path = stream.video.path
index = 0
videos = item.main_videos()
if index > len(videos):
raise Http404
f = videos[index]
path = stream.video.path
#server side cutting
#FIXME: this needs to join segments if needed
t = request.GET.get('t')
if t:
t = map(float, t.split(','))
ext = os.path.splitext(profile)[1]
ext = '.%s' % format
content_type = mimetypes.guess_type(path)[0]
if len(t) == 2 and t[1] > t[0] and stream.info['duration']>=t[1]:
response = HttpResponse(extract.chop(path, t[0], t[1]), content_type=content_type)