[Thomson] SDDRIVE Vidéo

Cette catégorie traite de développements récents pour nos vieilles machines, applications, jeux ou démos... Amis programmeurs, c'est ici que vous pourrez enfin devenir célèbres!

Modérateurs : Papy.G, fneck, Carl

__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

L'harmonique qui m'a sauté aux yeux est celle que j'ai pointé d'une flèche. Son amplitude est paradoxalement forte vis à vis de sa fréquence, c'est ce qui me donne l'impression que le son est joué plus "haut". Visuellement sa fréquence est un peu en dessous 7 khz, ce qui est très élevé, environ 140 cycles cpu. Comme la boucle du player est à 199cycles, ca ne colle pas.
[Edit]
Enregistrement en sortie de MO5 avec SDDRIVE : http://dcmoto.free.fr/tmp/440Hz.wav
Sur les Thomson la sortie son est pas mal parasitée par l'activité sur le bus, je ne sais pas si c'est facile à analyser.
En fait le son est très bon sans la variation que j'observe dans DCMoto.

On observe bien un pic à 440hz (ou presque). Il est très propre. Apparaissent aussi 2 pics entre 4 et 5khz qui sont très visibles. Je ne sais pas trop à quoi ils correspondent, mais dans tous les cas le spectre est bien moins polué par les harmoniques de DCMoto.
i4.png
i4.png (680.22 Kio) Consulté 6074 fois
Si je fait jouer DCMoto à 12khz le son n'est pas très bon. On entends un battement régulier très désagréables sur les 3 dernières secondes (ce qu'on voit aussi clairement sur le spectre)
i5.png
i5.png (982.98 Kio) Consulté 6078 fois
La période des battements est exactement 200ms, cad 1000 fois la période du player. J'ai du mal à y voir une simple coincidence.

A 6khz, DCMoto ne fait plus entendre de variations dans les harmoniques. C'est même plutôt très régulier et très propre. Rien à voir avec les battements du mode 12khz.
i6.png
i6.png (1.03 Mio) Consulté 6071 fois
On voit bien la porteuse à 440hz et deux pics intense à 5800hz et 6600hz environ.

En fait à partir de ces deux pics, je pense pouvoir affirmer que DCMoto n'échantillone pas à 6khz exactement mais plutôt à 6.2khz. En effet on a 6.2-0.4 = 5.8 et 6.2+ 0.4 = 6.6 c'est à dire qu'on peut expliquer les deux pics prononcés à 5.8 et 6.6khz par le repliement du pic "signal" de 440hz si et seulement si DCMoto tourne à 6.2khz au lieu de 6khz. C'est quand même cool ce qu'on peut tirer de l'analyse d'un simple signal audio. B)
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17316
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

On ne peut rien cacher à __sam__ :lol:
Dcmoto échantillonne à 25kHz, 12,5kHz, 6,25kHz et 3,125kHz. Dans la boîte de dialogue "Options" il n'y avait pas assez de place pour les décimales, alors j'ai arrondi. Je viens de corriger, ce sera juste dans la prochaine version de dcmoto_nouveau.
Daniel
L'obstacle augmente mon ardeur.
Daniel
Messages : 17316
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

Nouveaux enregistrements en sortie du MO5, pour les mélomanes qui n'ont pas encore SDDRIVE.
Mot de passe pour décompresser les fichiers .zip : sddrive
(Il y a un mot de passe car je n'ai pas les droits sur les œuvres enregistrées).
spinning money amours (disponibles 30 jours)
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Pour ceux que cela intéresse, j'ai mis le dernier source mon convertisseur visible >>ici<<. Le player est quant à lui visible >>là<<.

Le convertisseur n'est pas fini. Il est en version alpha. Il peut produire un fichier SD noir et blanc ou couleur suivant un flag. Il est conçu pour adapter automatiquement les paramètres de sorte à toujours tenir le FPS minimal (par défaut 10). Si la video est difficile à compresser (beaucoup de changements de plans par exemple) il va réduire la taille des images pour que qu'elles tiennent dans le débit disponible (environ 15ko/sec avec le player, soit seulement 1.5ko par image à 10fps). A l'inverse si la vidéo est facile à compresser (images plus ou moins statiques), il peut même augmenter le fps pour utiliser la bande passante au mieux. Durant la conversion s'affiche un truc comme ca:

Code : Tout sélectionner

(0) C:\sdvideo\tools> lua.exe conv_sd.lua "../Retro Game One 1x11 Programmeurs de génie cut.flv"
(1) ../Retro Game One 1x11 Programmeurs de génie cut.flv
(2) > 67x50 (4:3) 591.56s at 19fps
(3) > 100% 0:09:51 (1.3x) e=0.995 a=(x+0)*1
La ligne (1) reprends le nom du fichier vidéo passé en argument (voir commande dos en ligne (0)).

La ligne (2) indique la taille de la video ainsi que son format. Ici c'est 67x50 pour une taille maxi de 80x50, et un format 4:3. Cela veut dire que la bande passante permet à la vidéo d'être pleine hauteur. Nota avec un format plus "large" comme 16:9 on aurait probablement eu une vidéo pleine largeur de 80 pixels. Sont aussi indiqués la durée approximative de la video et la vitesse à laquelle on va la jouer. Ici on est à 19fps au lieu des 10fps de base ce qui veut dire que la bande passante a permis de presque doubler le débit.

La ligne (3) donne le pourcentage de traitement ainsi que le time-code de l'image en cours de traitement. La valeur qui précède le "x" est la vitesse d'encodage par rapport au temps réel. Ici on encode à 1.3 fois le temps réel par exemple, donc 5mins de vidéo prennent 5/1.3=3.8 minutes à être compressées. La valeur e=0.nnn qui suit est importante, elle donne l'efficacité du codage (c'est la fraction d'image tenant pile dans le débit). En gros c'est un nombre inférieure à 1 et plus il est proche de 1, meilleure sera la vidéo car beaucoup d'images seront décodables intégralement dans le temps imparti par le FPS. Un bonne vidéo tourne entre e=0.985 et e=0.999, et une moyenne vers 0.975, et plus bas la qualité n'est pas terrible car même si 97% des images apparaissent complètes, l’œil analyse les 3% incomplètes comme des défauts bien visibles (en tout cas pour mes yeux à moi). Enfin le a=(x+0)*1 permet d'avoir une idée de comment le son est ajusté par rapport à la source pour le thomson (le convertisseur égalise le son pour qu'il soit plein volume sur thomson). Je ne détaillerais pas plus cette partie, c'est la même chose que pour le script de SDANIM7 de l'époque.

Pour aller plus loin, j'ai backupé mon dossier de travail >>ici<<. Il contient deux sous-dossiers "sd_col" et "sd_gry" qui contiennent pleins de fichiers SD respectivement en couleur et en noir et blanc. Il y a de tout, cela me sert pour les tests.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

J'ai donc fait:

Code : Tout sélectionner

$ tools/lua.exe tools/conv_sd.lua ../call_on_me/MMD6\ -\ Bad\ Apple\ \(3D\ animation\ version\)\ \(Low\).mp4
../call_on_me/MMD6 - Bad Apple (3D animation version) (Low).mp4
> 60x45 (4:3) 224.05s at 10fps
> 100% 0:03:44 (1.5x) e=0.987 a=(x-1)*1

$ tools/lua.exe tools/conv_sd.lua ../call_on_me/Touhou\ -\ Bad\ Apple\!\!\(Shadow\ Art\)\ \(HD\).mp4
../call_on_me/Touhou - Bad Apple!!(Shadow Art) (HD).mp4
> 65x48 (4:3) 219.08s at 10fps
> 100% 0:03:39 (1.0x) e=0.992 a=(x-4)*1
ce qui donne :arrow: bad_apple.zip (lien temporaire)
Curieusement, la version N&B n'est pas plus fluide que la version couleur: 10fps plein écran pour les deux. Pourtant j'aurais dit que la version N&B aurait du avoir beaucoup moins de changements vidéos que la version couleur. Manifestement ca n'est pas le cas. Je pense que ce qui "tue" la performance en N&B sont les très nombreuses inversions vidéo complètes de l'écran qui imposent naturellement de ré-écrire l’intégralité de la mémoire vidéo.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17316
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

Après avoir passé les deux en boucle sur le MO5, le choix est vite fait : la version noir et blanc est sans intérêt par rapport à la version couleur.
Le noir et blanc se justifie s'il apporte une meilleure définition ou une meilleure fluidité. Dans ce cas il n'apporte qu'une absence de couleur.

Le plus surprenant est la qualité obtenue : le débit de lecture de la carte SD est six fois moins élevé qu'avec SDANIM7, mais la dégradation de l'image n'est pas (subjectivement) dans les mêmes proportions. Ou alors je m'habitue peut-être à la nouvelle définition ?

Exécutable Windows : SDDRIVE - Bad Apple (disponible 30 jours)
Daniel
L'obstacle augmente mon ardeur.
Avatar de l’utilisateur
6502man
Messages : 12286
Inscription : 12 avr. 2007 22:46
Localisation : VAR
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par 6502man »

Félicitations Sam pour ce nouveau player :D
Phil.

www.6502man.com

To bit or not to bit.
1 or 0.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Pour les amateurs: 1h de Brel à 29fps et aussi quelques pubs et la navette spatiale (mot de passe: sddrive)
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17316
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

Premières réactions après visualisation sur MO5 :
- Le son est bon. Je dirais presque excellent.
- La fluidité de l'image est remarquable pour un débit de 20 Ko/s
- Pour faire mieux il faudrait un débit de 160 Ko/s. J'y travaille :|

160 = 8 x 20. Vous comprenez ?
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Daniel a écrit : 01 sept. 2018 08:39 160 = 8 x 20. Vous comprenez ?
Oui oui :) (mais je suis peut-être le seul vu que personne n'a répondu depuis.)

De mon coté je suis rentré de vacance et teste un truc qui peut être intéressant pour le N&B. Voici ce que j'obtiens par exemple:

Code : Tout sélectionner

../call_on_me/Daft Punk - Get Lucky (Full Video).mp4
> 80x45 (16:9) 247.71s at 37fps
> 100% 0:04:07 (0.9x) e=0.987 a=(x-14)*1

../call_on_me/Dire Straits - Money For Nothing.mp4
> 67x50 (4:3) 299.98s at 25fps
> 100% 0:05:00 (1.1x) e=0.965 a=(x-89)*3

../call_on_me/Dire Straits - Private Investigations.mp4
> analyzing.../ 91%
> 67x50 (4:3) 346.37s at 24fps
> 7% 0:00:25 (1.3x) e=0.990 a=(x-119)*8
> 100% 0:05:46 (1.2x) e=0.982 a=(x-102)*5

../call_on_me/Amiga Trackmo  World of Commodore 92 _ Sanity (1992) HQ.mp4
> 63x50 (5:4) 588.67s at 45fps
> 100% 0:09:48 (0.9x) e=0.975 a=(x-20)*1
(En gros ca double le FPS). Des fois ca rend bien, et d'autres fois c'est moyen. C'est peut-être une fausse bonne idée...
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Daniel
Messages : 17316
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par Daniel »

Avec cette faible définition de l'image, quoi qu'on fasse, toutes les vidéos ne passent pas bien. Quand on connaît l'original on reconnaît, par contre dans certains cas il est difficile d'imaginer.

La solution est de choisir des images pas trop détaillées. En couleur ça passe mieux, en particulier Bad Apple. Ou alors, en noir et blanc, du dessin au trait avec décor fixe, comme Simon's cat. Même avec mon algorithme ultra simple la fluidité n'est pas mauvaise et le dessin bien reconnaissable.

Il reste que le son est excellent dans tous les cas, au moins pour mes oreilles imparfaites. Je crois que le gap entre les blocs ne s'entend pas.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Le gap inter-bloc est compensé par le player :) Pour le son, oui même à 5khz ca reste très bon. C'est d'ailleurs la fréquence de mon mod-player.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Daniel a écrit : 21 août 2018 08:44 @__sam__ : Si tu es rentré de vacances, je t'offre immédiatement un contrôleur SDDRIVE, sinon j'attends ton retour.
Reçu aujourd'hui. Merci Daniel! 8)

Aussitôt monté sur le TO8D et testé

(excusez la qualité vidéo et audio, j'ai fait ca en toute hâte[*])

En fait, ca marche plutôt très bien. Je ne sais pas si cela ne se remarque pas sur la vidéo, mais j'ai amélioré la compression et atteint souvent le plein écran tout en réduisant l'effet de "vague" qui apparaît lors des changements de plans ou les panning rapides. Globalement la qualité est bien meilleure.

Code : Tout sélectionner

-- conversion fichier video en fichier sd-drive
--
-- version alpha 0.01
---
-- Samuel DEVULDER Aout 2018

-- code experimental. essaye de determiner
-- les meilleurs parametres (fps, taille ecran
-- pour respecter le fps ci-dessous. 

-- gray peut être true ou false suivant qu'on
-- veut une sortie couleur ou pas. Le gris est
-- generalement plus rapide et/ou avec un ecran
-- plus large.

-- Work in progress!
-- le code doit être nettoye et rendu plus
-- amical pour l'utilisateur

local function round(x)
	return math.floor(x+.5)
end

local tmp = 'tmp'
local img_pattern =  tmp..'/img%05d.bmp'
local cycles = 199 -- cycles par échantillons audio
local hz = round(8000000/cycles)/8
local fps = 10
local gray = false
local interlace = false --gray
local dither = 2
local ffmpeg = 'tools\\ffmpeg'
local mode = nil

local file = arg[1]:gsub('^/cygdrive/(%w)/','%1:/')

local function exists(file)
   local ok, err, code = os.rename(file, file)
   if not ok then
      if code == 13 then
         -- Permission denied, but it exists
         return true
      end
   end
   return ok, err
end

local function isdir(file)
	return exists(file..'/')
end

if not exists(file) then os.exit(0) end

local function percent(x)
	return round(math.min(1,x)*100)
end

local function hms(secs, fmt)
	secs = round(secs)
	return string.format(fmt or "%d:%02d:%02d", 
			math.floor(secs/3600), math.floor(secs/60)%60, math.floor(secs)%60)
end

-- if file:match('miga') then
	-- gray = false
	-- interlace = false
-- end

-- nom fichier
io.stdout:write('\n'..file..'\n')
io.stdout:flush()

-- recherche la bonne taille d'image
local x,y = 80,45
local IN,line = assert(io.popen(ffmpeg..' -i "'..file ..'" 2>&1', 'r'))
for line in IN:lines() do 
	local h,m,s = line:match('Duration: (%d+):(%d+):(%d+%.%d+),')
	if h and m and s then duration = h*3600 + m*60 +s end
	local a,b = line:match(', (%d+)x(%d+)')
	if a and b then x,y=a,b end
end
IN:close()
if not duration then error("Can't get duration!") end
local max_ar
for i=2,10 do
	local t = x*i/y
	t = math.abs(t-round(t))
	if max_ar==nil or t<max_ar then
		max_ar = t
		aspect_ratio = round(x*i/y)..':'..i
	end
end
local w = 80
local h = round(w*y/x)
if h>50 then
   h = 50
   w = round(h*x/y)
end

if mode==nil then
	mode = (h*w>32*48 and 'i') or 'p'
end

-- initialise la progression dans les octets de l'image
local lines = {}
for i=math.floor((50-h)/2)*4,(math.floor((50-h)/2)+h)*4-1 do
	if i%4<3 then
		table.insert(lines, i)
	end
end
if mode=='p' then
	-- rien
elseif mode=='i' then
	local t = {}
	for i=1,#lines,2 do
		table.insert(t, lines[i])
	end
	for i=2,#lines,2 do
		table.insert(t, lines[i])
	end
	lines = t
elseif mode=='r' then
	local size = #lines
	for i = size, 1, -1 do
		local rand = math.random(size)
		lines[i], lines[rand] = lines[rand], lines[i]
	end
else 
	error('Unknown mode: ' .. mode)
end
local indices = {}
for _,i in ipairs(lines) do
	-- print(i)
	for j=i*40,i*40+39 do
		table.insert(indices, j)
	end
end
-- os.exit(0)
-- flux audio
local AUDIO = {}
function AUDIO:new(file, hz)
	local o = {
		stream = assert(io.popen(ffmpeg..' -i "'..file ..'" -v 0 -f u8 -ac 1 -ar '..round(8*hz)..' -acodec pcm_u8 -', 'rb')),
		cor = {8,255}, -- volume auto
		buf = '', -- buffer
		running = true
	}
	setmetatable(o, self)
	self.__index = self
	return o
end
function AUDIO:close()
	self.stream:close()
end
function AUDIO:next_sample()
	local buf = self.buf
	if buf:len()<=8 then
		local t = self.stream:read(65536)
		if not t then 
			self.running = false
			t = string.char(0,0,0,0,0,0,0,0)
		end
		buf = buf .. t
	end
	local v = (buf:byte(1) + buf:byte(2) + buf:byte(3) + buf:byte(4) +
				buf:byte(5) + buf:byte(6) + buf:byte(7) + buf:byte(8))*.125
	self.buf = buf:sub(9)
	-- auto volume
	if v<self.cor[2]     then self.cor[2]=v end
	v = v-self.cor[2]
	if v*self.cor[1]>255 then self.cor[1]=255/v end
	v = v*self.cor[1]
	-- dither
	v = math.min(v + math.random(0,3), 255)
	return math.floor(v/4)
end

-- flux video
local VIDEO = {}
function VIDEO:new(file, w, h, fps, gray)
	if isdir(tmp) then
		os.execute('del >nul /s /q '..tmp)
	else
		os.execute('md '..tmp)
	end

	local o = {
		cpt = 1, -- compteur image
		width = w,
		height = h,
		fps = fps or 10,
		gray = gray or false,
		image = {},
		dither = nil,
		expected_size = 54 + h*(math.floor((w*3+3)/4)*4),
		running=true,
		streams = {
			inp = assert(io.open(file, 'rb')),
			out = assert(io.popen(ffmpeg..' -i - -v 0 -r '..fps..' -s '..w..'x'..h..' -an '..img_pattern, 'wb')),
		}
	}
	setmetatable(o, self)
	self.__index = self
	for i=0,7999+3 do o.image[i]=0 end
	return o
end
function VIDEO:close()
	if io.type(self.streams.inp)=='file' then self.streams.inp:close() end
	if io.type(self.streams.out)=='file' then self.streams.out:close() end
end
function VIDEO:init_dither()
	local function bayer(t)
		local m=#t
		local n=#t[1]
		local d={}
		for i=1,2*m do
			d[i] = {}
			for j=1,2*n do
				d[i][j] = 0
			end
		end
		for i=1,m do
			for j=1,n do
				local z = 4*t[i][j]
				d[m*0+i][n*0+j] = z-3
				d[m*1+i][n*1+j] = z-2
				d[m*1+i][n*0+j] = z-1
				d[m*0+i][n*1+j] = z-0
			end
		end
		return d
	end
	local m = {{1}}
	for i=1,dither do m = bayer(m) end
	local x = 0
	for i=1,#m do
		for j=1,#m[1] do
			x = math.max(x, m[i][j])
		end
	end
	x = 1/(x + 1)
	for i = 1,#m do
		for j = 1,#m[1] do
			m[i][j] = m[i][j]*x
		end
	end
	m.w = #m
	m.h = #m[1]
	function m:get(i,j)
		return self[1+(i % self.w)][1+(j % self.h)]
	end
	self.dither = m
end
function VIDEO:linear(u)
	return u<0.04045 and u/12.92 or (((u+0.055)/1.055)^2.4)
end
function VIDEO:pset(x,y, r,g,b)
	if not self._linear then
		self._linear = {}
		for i=0,255 do self._linear[i] = self:linear(i/255) end
	end
	r,g,b = self._linear[r],self._linear[g],self._linear[b]
	if not self.dither then VIDEO:init_dither()	end
	local d = self.dither:get(x,y)
	
	if not self._pset then
		self._pset = {}
		self._pset[0] = {}
		self._pset[1] = {}
		for i=0,15 do
			self._pset[0][i] = {}
			self._pset[1][i] = {}
			for j=0,3 do
				self._pset[0][i][j] = (i%4)     + 4*j
				self._pset[1][i][j] = (i-(i%4)) +   j
			end
		end
	end
	local o,p = x%2,math.floor(x/2) + y*160
	local function v(v) 
		-- assert(0<=v and v<=3, 'v=' .. v)
		self.image[p] = self._pset[o][self.image[p]][v]
		p = p+40
	end	
	if interlace then
		local q = self.cpt%2 == 0
		function v(v) 
			if q then
				self.image[p] = self._pset[o][self.image[p]][v]
				q = false
			else
				q = true
			end
			p = p+40
		end	
	end
	
	if self.gray then
		r = (.2126*r + .7152*g + .0722*b)*9 + d
		if     r>=4 then	v(3)
		elseif r>=2 then	v(2)
		elseif r>=1 then	v(1)
		else 				v(0)	
		end
		if     r>=7 then	v(3)
		elseif r>=5 then	v(2)
		elseif r>=3 then	v(1)
		else 				v(0)	
		end
		if     r>=9 then	v(3)
		elseif r>=8 then	v(2)
		elseif r>=6 then	v(1)
		else 				v(0)	
		end
	else
		v(math.floor(r*3 + d))
		v(math.floor(g*3 + d))
		v(math.floor(b*3 + d))
	end
end
function VIDEO:read_bmp(bytecode) -- (https://www.gamedev.net/forums/topic/572784-lua-read-bitmap/)
	-- Helper function: Parse a 16-bit WORD from the binary string
	local function ReadWORD(str, offset)
		local loByte = str:byte(offset);
		local hiByte = str:byte(offset+1);
		return hiByte*256 + loByte;
	end

	-- Helper function: Parse a 32-bit DWORD from the binary string
	local function ReadDWORD(str, offset)
		local loWord = ReadWORD(str, offset);
		local hiWord = ReadWORD(str, offset+2);
		return hiWord*65536 + loWord;
	end
	
	-------------------------
	-- Parse BITMAPFILEHEADER
	-------------------------
	local offset = 1;
	local bfType = ReadWORD(bytecode, offset);
	if(bfType ~= 0x4D42) then
		error("Not a bitmap file (Invalid BMP magic value)");
		return;
	end
	local bfOffBits = ReadWORD(bytecode, offset+10);

	-------------------------
	-- Parse BITMAPINFOHEADER
	-------------------------
	offset = 15; -- BITMAPFILEHEADER is 14 bytes long
	local biWidth = ReadDWORD(bytecode, offset+4);
	local biHeight = ReadDWORD(bytecode, offset+8);
	local biBitCount = ReadWORD(bytecode, offset+14);
	local biCompression = ReadDWORD(bytecode, offset+16);
	if(biBitCount ~= 24) then
		error("Only 24-bit bitmaps supported (Is " .. biBitCount .. "bpp)");
		return;
	end
	if(biCompression ~= 0) then
		error("Only uncompressed bitmaps supported (Compression type is " .. biCompression .. ")");
		return;
	end

	---------------------
	-- Parse bitmap image
	---------------------
	local ox = math.floor((80 - biWidth)/4)*2
	local oy = math.floor((50 - biHeight)/2)
	local oo = 4*math.floor((biWidth*biBitCount/8 + 3)/4)
	for y = biHeight-1, 0, -1 do
		offset = bfOffBits + oo*y + 1;
		for x = ox, ox+biWidth-1 do
			self:pset(x, oy, 
					  bytecode:byte(offset+2), -- r
					  bytecode:byte(offset+1), -- g
					  bytecode:byte(offset));  -- b
			offset = offset + 3;
		end
		oy = oy+1
	end
end
function VIDEO:next_image()
	if not self.running then return end
	
	-- nom nouvelle image
	local name = img_pattern:format(self.cpt); self.cpt = self.cpt + 1
	local buf = ''
	local f = io.open(name,'rb')
	if f then 
		buf = f:read(self.expected_size) or buf
		f:close()
	end
		
	-- si pas la bonne taille, on nourrit ffmpeg
	-- jusqu'a obtenir un fichier BMP complet
	local timeout = 5
	while buf:len() ~= self.expected_size and timeout>0 do
		buf = self.streams.inp:read(65536)
		if buf then
			self.streams.out:write(buf)
			self.streams.out:flush()
		else 
			if io.type(self.streams.out)=='file' then
				self.streams.out:close()
			end
			-- io.stdout:write('wait ' .. name ..'\n')
			-- io.stdout:flush()
			local t=os.time()+1
			repeat until os.time()>t
			timeout = timeout - 1
		end
		f = io.open(name,'rb')
		if f then 
			buf = f:read(self.expected_size) or ''
			f:close()
			timeout = 5
		else
			buf = ''
		end
	end
	
	-- effacement temporaire
	os.remove(name)

	if buf and buf:len()>0 then 
		-- nettoyage de l'image précédente
		-- for i=0,7999+3 do self.image[i]=0 end
		-- lecture image
		self:read_bmp(buf)
	else
		self.running = false
	end
end
function VIDEO:skip_image()
	local bak = self.pset
	self.pset = function() end
	self:next_image()
	self.pset = bak
end

-- auto determination des parametres
local stat = VIDEO:new(file,w,h,round(fps/2),gray)
stat.super_pset = stat.pset
stat.histo = {n=0}; for i=0,255 do stat.histo[i]=0 end
function stat:pset(x,y, r,g,b)
	stat.histo[r] = stat.histo[r]+1
	stat.histo[g] = stat.histo[g]+1
	stat.histo[b] = stat.histo[b]+1
	self:super_pset(x,y,r,g,b)
end
stat.super_next_image = stat.next_image
stat.mill = {'|', '/', '-', '\\'}
stat.mill[0] = stat.mill[4]
function stat:next_image()
	self:super_next_image()
	io.stderr:write(string.format('> analyzing...%s %d%%\r', self.mill[self.cpt % 4], percent(self.cpt/self.fps/duration)))
	io.stderr:flush()
end
stat.trames = 0
stat.prev_img = {}
for i=0,7999 do stat.prev_img[i]=-1 end
function stat:count_trames()
	local pos,prev,curr = 0,stat.prev_img,stat.image
	for _,i in ipairs(indices) do
	-- for i=0,7999 do
		if prev[i] ~= curr[i] then 
			stat.trames = stat.trames + 1
			local k = i - pos
			if k<0 then k=8000 end
			if k<=2 then
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
			elseif k<=256 then
				pos = i
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
			else
				pos = i
				prev[pos] = curr[pos]; pos = pos+1
			end
		end
	end
end
while stat.running do
	stat:next_image()
	stat:count_trames()
end
io.stderr:write(string.rep(' ',79)..'\r')
io.stderr:flush()
local max_trames = 1000000/fps/cycles
local avg_trames = (stat.trames/stat.cpt) * 1.03 -- 11% safety margin
local ratio = max_trames / avg_trames
if ratio>1 then
	fps = math.min(math.floor(fps*ratio),interlace and 50 or 25)
elseif ratio<1 then
	local zoom = ratio^.5
	w=math.floor(w*zoom)
	h=math.floor(h*zoom)
end
stat.total = 0
for i=1,255 do
	stat.total = stat.total + stat.histo[i]
end
stat.threshold_min = (gray and .03 or .03)*stat.total
stat.min = 0
for i=1,255 do
	stat.min = stat.min + stat.histo[i]
	if stat.min>stat.threshold_min then
		stat.min = i-1
		break
	end
end
stat.max = 0
stat.threshold_max = (gray and .03 or .05)*stat.total
for i=254,1,-1 do
	stat.max = stat.max + stat.histo[i]
	if stat.max>stat.threshold_max then
		stat.max = i+1
		break
	end
end
-- print(stat.min, stat.max)
-- io.stdout:flush()
local video_cor = {stat.min, 255/(stat.max - stat.min)}

-- fichier de sortie
function file_content(file, size)
	local INP = assert(io.open(file, 'rb'))
	local buf = ''
	while true do
		local t = INP:read(256)
		if not t then break end
		buf = buf .. t .. string.rep(string.char(0),512-t:len())
	end
	size = size - buf:len()
	if size<0 then
		print('size',size)
		error('File ' .. file .. ' is too big')
	end
	return buf .. string.rep(string.char(0),size)
end

local OUT = assert(io.open(file:gsub('.*[/\\]',''):gsub('%.[%a%d]+','')..'.sd', 'wb'))
OUT:write(file_content('bin/bootblk.raw', 512))
OUT:write(file_content(gray and 'bin/player1.raw' or 'bin/player0.raw', 7*512))

-- flux audio/video
local audio  = AUDIO:new(file, hz)
local video  = VIDEO:new(file,w,h,fps,gray)

-- adaptation luminosité
video.super_pset = video.pset
function video:pset(x,y, r,g,b)
	local function f(x)
		x = round((x-video_cor[1])*video_cor[2]);
		return x<0 and 0 or x>255 and 255 or x
	end
	self:super_pset(x,y, f(r),f(g),f(b))
end

-- vars pour la cvonvesion
local start          = os.time()
local tstamp         = 0
local cycles_per_img = 1000000 / fps
local current_cycle  = 0
local completed_imgs = 0
local pos            = 8000
local blk            = ''

-- init previous image
local curr = video.image
local prev = {}
for i=0,7999+3 do prev[i] = -1 end

function test_fin_bloc()
	if blk:len()==3*170 then
		local s1 = audio:next_sample()
		local s2 = audio:next_sample()
		local s3 = audio:next_sample()
		local t = s1*1024 + math.floor(s2/2)*32 + math.floor(s3/2)
	
		blk = blk .. string.char(math.floor(t/256), t%256)
		OUT:write(blk)
		blk = ''

		current_cycle = current_cycle + cycles*3
	end
end

-- conversion
io.stdout:write(string.format('> %dx%d %s (%s) %s at %d fps (%d%% zoom)\n',
	w, h, mode, aspect_ratio,
	hms(duration, "%dh %dm %ds"), fps, percent(math.max(w/80,h/50))))
io.stdout:flush()
video:next_image()
while audio.running do
	-- infos
	if video.cpt % video.fps == 0 then
		tstamp = tstamp + 1
		local d = os.time() - start; if d==0 then d=1000000000 end
		local t = "> %d%% %s (%3.1fx) e=%5.3f a=(x%+d)*%.1g         \r"
		t = t:format(
			percent(tstamp/duration), hms(tstamp),
			round(100*tstamp/d)/100, completed_imgs/video.cpt,
			-audio.cor[2], audio.cor[1])
		io.stdout:write(t)
		io.stdout:flush()
	end
	
	for _,i in ipairs(indices) do
	-- for i=0,7999 do
		if prev[i] ~= curr[i] then 
			local k = i - pos
			if k<0 then k=8000 end
			pos = i
			local buf = {audio:next_sample()*4,0,0}
			-- if mode=='i' and w==80 then
				-- if k<=2 and ((pos-k)%40)+4>=40
			-- end
			
			if k<=2 then
				-- deplacement trop faible: mise a jour des 4 octets
				-- videos suivants d'un coup
				pos = pos - k
				buf[1] = buf[1] + 1
				buf[2] = curr[pos+0]*16 + curr[pos+1]
				buf[3] = curr[pos+2]*16 + curr[pos+3]
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
			elseif k<=256 then
				-- deplacement 8 bit
				buf[1] = buf[1] + 0
				buf[2] = k%256
				buf[3] = curr[pos+0]*16 + curr[pos+1]
				prev[pos] = curr[pos]; pos = pos+1
				prev[pos] = curr[pos]; pos = pos+1
			else
				-- deplacement arbitraire
				buf[1] = buf[1] + 2 + math.floor(pos/4096)
				buf[2] = math.floor(pos/16) % 256
				buf[3] = (pos%16)*16 + curr[pos]
				prev[pos] = curr[pos]; pos = pos + 1
			end
			blk = blk .. string.char(buf[1], buf[2], buf[3])
			current_cycle = current_cycle + cycles
			
			test_fin_bloc()
		end
	end
	completed_imgs = completed_imgs + 1
	
	-- skip image if drift is too big
	while current_cycle>2*cycles_per_img do
		video:skip_image()
		if video.cpt % video.fps == 0 then
			tstamp = tstamp + 1
		end
		current_cycle = current_cycle - cycles_per_img
	end		
	
	-- add padding if image is too simple
	while current_cycle<cycles_per_img do
		blk = blk .. string.char(audio:next_sample()*4+2,0,curr[0])
		pos = 1
		current_cycle = current_cycle + cycles
		test_fin_bloc()
	end
	
	-- next image
	video:next_image()
	current_cycle = current_cycle - cycles_per_img
end
test_fin_bloc()
blk = blk .. string.char(3,255,255)
OUT:write(blk .. string.rep(string.char(255),512-blk:len()))
OUT:close()
audio:close()
video:close()
io.stdout:write('\n')
io.stdout:flush() 	
_____
[*] hum la qualité ne doit pas être si mauvaise que ca vu que youtube a carrément bloqué la vidéo dans tous les pays. Je ne sais pas quoi faire pour que ca passe quand même.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Avatar de l’utilisateur
fneck
Site Admin
Messages : 17424
Inscription : 01 avr. 2007 12:03
Localisation : Drôme Provençale (26)
Contact :

Re: [Thomson] SDDRIVE Vidéo

Message par fneck »

@ Sam, la vidéo ne passe pas chez moi:
Vidéo non disponible
Cette vidéo inclut du contenu de WMG, qui l'a bloquée dans votre pays pour des raisons de droits d'auteur.
Fabien https://www.system-cfg.com
Les bonnes pratiques de l'utilisateur du forum viewtopic.php?f=14&t=3
__sam__
Messages : 7923
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] SDDRIVE Vidéo

Message par __sam__ »

Oui Warner fait suer! J'ai recu ce mail
Bonjour Samuel Devulder,

Suite à une réclamation pour atteinte aux droits d'auteur, votre vidéo YouTube a été bloquée. Par conséquent, les utilisateurs ne peuvent plus la regarder sur YouTube.

Titre de la vidéo : SDDrive jouant des vidéos
Contenu protégé par des droits d'auteur : Spinning Around
Revendiquée par : WMG
Du coup, pour me venger voici le fichier SD sans protection: >>ICI<<
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Répondre