sobota, lipca 19, 2008

Turning SE K550i into mp4 player

Przez ten weekend pobawiłem się trochę moją nową komórką - Sony-Ericssonem K550i. Jedną z jego funkcji jest możliwość odtwarzania filmów wideo w formacie MP4. Tak sobie pomyślałem, że fajnie by było zgrać trochę ulubionych klipów z YouTube na komórkę jako empeczwórki. Pytanie tylko jak albo za pomocą czego? Dodam, że chciałem to zrobić na Linuksie, więc wszystkie konwertery dostępne w takich pakietach jak PC Suite dostarczanych wraz telefonem odpadają. Najpierw poszperałem trochę po necie by się doszkolić (google najlepszym nauczycielem). Szybko znalazłem sobie rozszerzenie do Firefoksa spełniające moje oczekiwania - DownloadHelper. Za pomocą niego można łatwo pobrać klipy w formacie Flash Video (FLV). Teraz trzeba ulubiony klip tylko prze konwertować. Najpierw próbowałem skryptów znalezionych w sieci, ale już po pierwszych niepowodzeniach postanowiłem napisać własny. Początkowo próbowałem sił w bashu, ale najpóźniej przy obliczeniach rozdzielczości z zastosowaniem zmiennych zmiennoprzecinkowych stwierdziłem, że chyba lepszym rozwiązaniem będzie skrypt pisany w pythonie. Poza tym odświeżyłem sobie używanie wyrażeń regularnych w Pythonie. No dobrze, ale wracając do skryptu. Wymaga on zainstalowanych dwóch programów w systemie:
  • exiftool (pobiranie metadanych z pliku video)
  • ffmpeg (konwersja do formatu MP4)

mp4-for-SE.py(Toggle Plain Text)

#!/usr/bin/python
# -*- coding: utf-8 -*-
# FLV-to-MP4 converter for Sony-Ericsson K550i
#
# Depends on ffmpeg and exiftool

import sys
import os
import re

add=0
episode = 300   # 5 minutes
width=220
height=176
DONT_SPLIT=False

# Get input & output
try:
    fin=sys.argv[1]
    p=re.compile(r'\.\w*$')
    m=p.search(fin)
    fout=fin.replace(m.group(0),"")
except:
    fin=""

if fin=="":
    print "Usage: mp4-for-SE.py INPUT"
else:
    # Get aspect ratio
    stdout_handle = os.popen("exiftool -Image\Width "+fin, "r")
    iwidth = stdout_handle.read()
    stdout_handle = os.popen("exiftool -Image\Height "+fin, "r")
    iheight = stdout_handle.read()
    try:
        p1=re.compile(r'Image Width\s*:\s*')
        p2=re.compile(r'Image Height\s*:\s*')
        m1=p1.match(iwidth)
        m2=p2.match(iheight)
        iwidth=iwidth.replace(m1.group(0),"")
        iheight=iheight.replace(m2.group(0),"")
        iwidth=iwidth.replace("\n","")
        iheight=iheight.replace("\n","")
        src_aspect=float(iwidth)/float(iheight)
        dest_aspect=float(width)/float(height)
        if src_aspect>dest_aspect:
            height=int(float(width)/src_aspect)
            if (height % 2 <> 0):
                height+=1
        else:
            width=int(float(height)/src_aspect)
            if (width % 2 <> 0):
                width+=1
    except:
        pass

    stdout_handle = os.popen("exiftool -Duration "+fin, "r")
    str_duration = stdout_handle.read()
    # Basic preparation
    try:
        p=re.compile(r'Duration\s*:\s*')
        m=p.match(str_duration)
        str_duration=str_duration.replace(m.group(0),"")
        str_duration=str_duration.replace("\n","")
    except:
        print "Error: Can't get movie duration. Converting whole movie."
        DONT_SPLIT=True
        exit
    if DONT_SPLIT:
        counter=0
    else:
        # Format some youtube movies outputing duration as "xx:xx.xxxx s"
        p=re.compile(r'\.\d*\s*s')
        m=p.search(str_duration)
        try:
            str_duration=str_duration.replace(m.group(0),"")
            add=1
        except:
            pass
        duration=str_duration.split(":")
        s=int(duration[-1])
        try:
            m=int(duration[-2])
        except:
            m=0
        try:
            h=int(duration[-3])
        except:
            h=0
        total=h*3600+m*60+s+add
        print "\033[1;32mTotal time:\033[1;31m",total,"\033[1;39ms"
        counter = total/episode

    print "\033[1;32mTotal parts:\033[1;31m",counter+1,"\033[1;39m"
    for i in range(0,counter+1):
        if counter==0:
            os.system("ffmpeg -i "+fin+" -s "+str(width)+"x"+str(height)+" -ss "+str(i*episode)+" -t "+str(episode)+" -vcodec mpeg4 "+fout+".mp4")
        else:
            os.system("ffmpeg -i "+fin+" -s "+str(width)+"x"+str(height)+" -ss "+str(i*episode)+" -t "+str(episode)+" -vcodec mpeg4 "+fout+"["+str(i+1)+"].mp4")


Użycie ffmpega rozumie się samo przez się. Czemu exiftool? W celu wydobycia informacji o długości filmu. Problem był następujący. Komórka ma ograniczone zasoby pamięci i mocy obliczeniowej z tego powodu większe (ok. 10 minutowe) klipy nie zostają odtworzone. Wpadłem więc na pomysł, by ciąć film na 5-minutowe kawałki, a ponieważ wewnętrzny odtwarzać automatycznie przeskakuje do następnego klipu na liście po zakończeniu odtwarzania poprzedniego takie rozwiązanie się nawet sprawdza. Teoretycznie za pomocą tego skryptu można przerabiać nawet większe filmy np. divixy na serię 5 minutowych klipów, ale ja jedynie skrypt testowałem na filmach maksimum 15 minutowych. Jeśli dostępne są informacje o wymiarach kadru klip jest skalowany z zachowaniem proporcji do rozmiarów wyświetlacza telefonu. Zmniejsza to dodatkowo rozmiar filmu jeśli mamy do czynienia z ujęciem panoramicznym. Całość się nawet ładnie prezentuje i można spokojnie sobie obejrzeć jakiś film pełnometrażowy o ile wcześniej bateria nie wyzionie ducha ]:)

A tak to wygląda na telefonie (przepraszam za wygląd, ale blogger mi zmasakrował aspekt):

video


Na wypadek gdyby ktoś nie zauważył. Ta przerwa w filmie zanim bałwan płaci zielonymi portierowi to właśnie przeskok do następnego klipu.

7 komentarzy:

szefu_c_k pisze...

Ciekawe, ciekawe :) o zaletach ffmpega sam się ostatnio przekonałem , implementując odtwarzanie filmów (flv) na stronie. Kompresja z każdego formatu, dopasowanie rozdzielczości i jakości :) jedną linią jest okej ;). Jednak nie umiem znaleźć jakiegoś darmowego playera, który można zaimplementować na portalu mojego klienta. Skończyło się na wykupieniu licencji, co uważam za fair, gdyż kto ma nie wspierać OpenSource jak nie commerce section ;)

Lightnir pisze...

No tak ffmpeg powala. Ostatnio ulepszyłem trochę ten mój skrypt i teraz mogę sobie oglądać odcinki Stargate Atlantis na komórce. I wszystko za pomocą jednej komendy ]:)

Anonimowy pisze...

Witam! Mam tak samo se k550i, i u mnie odtwarza nawet godzinne filmy, bez żadnego cięcia... Konwertuję ffmpeg do formatu 3gp, kodek h263, adio aac. Pozdrawiam!

Anonimowy pisze...

Trzeba sciagac na kompie wszystkie odtwarzacze czy mozna zrobic to na fonie.?

Anonimowy pisze...

A ja mam pytanie czy na se k.,i mozna ogladac filmy bezposrednio na youtubie w fonie? I czy mozna sciagac programy przez telefon?

Lightnir pisze...

Na SE K550i nie można oglądać filmów bezpośrednio z youtube, bo telefon nie posiada flasha. O ile mi wiadomo takie coś możliwe jest na telefonach i urządzeniach mobilnych z zainstalowanym Flash Lite np. na Nokii N95. Ściągać na telefon można w zasadzie każdy plik dostępny przez www. Jak ktoś ma gruby portfel i nie wie co z pieniędzmi robić to proszę bardzo. Ja tam wolę surfować za pomocą komputera. Komórkę w tym celu używam sporadycznie.

Pi0trazy pisze...

Super art. Świetnie, że autor umieścił skrypcik. Ja ze swojej strony mogę podesłać coś takiego:

mencoder dvd://1 -dvd-device /dev/dvd -of lavf -lavfopts format=mp4 -oac lavc -ovc lavc -lavcopts aglobal=1:vglobal=1:acodec=libfaac\
:abitrate=128:vcodec=mpeg4\
:vbitrate=300:keyint=25 -ofps 25 -af lavcresample=44100 -vf harddup,scale=220:-3 -mc 0 -noskip -o MOVIE.mp4

Opisany przykład robi nam bezpośrednio z DVD plik mp4 który jest gotowy do wstawienia do telefonu. Ustawienia można jeszcze dopieścić. Niestety nie dzieli na wiele plików, tylko ciurkiem do jednego. W przypadku np. SE W610 to jest problem bo nie ma w nim przewijania filmów.