[Thomson] Vidéo avec son en streaming

Cette catégorie traite de développements récents destinés à 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

Daniel
Messages : 17408
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Vidéo avec son en streaming

Message par Daniel »

dcmoto 2015.07.03 disponible ici --> http://dcmoto.free.fr/emulateur/dcmoto_nouveau.zip
Le debugger n'incrémente plus l'index de la carte, mais il y a peut-être autre chose...
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Vidéo avec son en streaming

Message par __sam__ »

Oui il doit y avoir autre chose car je ne lis que $FF dans le code ASM précédent. Idem avec le code qui boucle sur le LDB <$CC.

Décidément, la mise au point du mode sans acquittement n'est pas simple.
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 : 17408
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Vidéo avec son en streaming

Message par Daniel »

J'ai fait le test suivant avec dcmoto 2015.07.03 en mode MO5 v2.1, option Contrôleur = Absent :

- Dans "Supports amovibles" cocher Interface SDMOTO et charger testbug.sd
testbug.sd.zip
(170 octets) Téléchargé 130 fois
- Dans le debugger charger en $9000 le fichier testbug.bin
testbug.bin.zip
(209 octets) Téléchargé 133 fois
- Mettre un point d'arrêt en $9033 (Exec, Normal) et cliquer sur Exécuter

- En Basic taper RUN &H9000 : le programme s'arrête en $9033 avec B=$00

- Dans le debugger cliquer sur Exécuter. A chaque fois le programme s'arrête en $9033 avec B=$01,$02,$03,....,$0E,$0F
C'est exactement le contenu du fichier testbug.sd

Le problème est peut-être dans le choix des options. Pour simuler l'Arduino il ne faut pas cocher le contrôleur CS91280 dans les options et cocher "Interface SDMOTO" dans "Supports amovibles", avec un fichier .sd chargé. Mais il faut aussi que le bit 6 de $A7CD soit en sortie et le bit 7 en entrée. Ce n'est pas très intuitif, je remplacerai cela dans une prochaine version par une case à cocher "Interface Arduino".
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Vidéo avec son en streaming

Message par __sam__ »

Daniel a écrit :et cocher "Interface SDMOTO" dans "Supports amovibles"
Mince, quel imbécile je fais: c'était uniquement celà. Groumph... j'ai l'air bête du coup.

Voici donc le player

Code : Tout sélectionner

10 CLEAR,&H8FFF
20 COLOR7,0:SCREEN,,0:CLS:LOCATE0,0,0
25 CONSOLE,,0:FORI=0TO199:LINE(0,I)-(319,I),2^(I MOD3):NEXT:CONSOLE,,1:CLS
30 READ A$:IF LEN(A$)=4 THEN A=VAL("&H"+A$):GOTO 30
40 IF A$="**" THEN EXEC A ELSE POKE A,VAL("&H"+A$):A=A+1:GOTO 30
50 DATA 9000
60 DATA 34,7F,1A,50,8E,1F,40,E6,84,63
70 DATA 84,E1,84,27,0A,63,84,CE,A7,C0
80 DATA 8E,00,00,20,06,CE,E7,C3,8E,40
90 DATA 00,BF,90,48,BF,90,58,BF,90,68
100 DATA A6,C4,8A,01,A7,C4,1F,30,1F,8B
110 DATA 4F,5F,DD,CE,C6,7F,DD,CC,8A,04
120 DATA 97,CE,97,CF,D6,CC,27,03,3A,20
130 DATA 05,8E,40,00,20,00,D6,CC,E7,84
140 DATA D6,CC,27,03,3A,20,05,8E,40,00
150 DATA 20,00,D6,CC,E7,84,D6,CC,27,03
160 DATA 3A,20,05,8E,40,00,20,00,D6,CC
170 DATA E7,84,96,CC,97,CD,2B,CA,35,FF
180 DATA 9000,**
Pour afficher un bout d'indiana-jones à 42 images par seconde (plein écran): http://www.cjoint.com/doc/15_07/EGekhnO ... r-Scene.7z

Convertisseur:

Code : Tout sélectionner

#/bin/perl

##############################################################################
# Conversion de fichier video en fichier SD fonctionnant avec le
# player SDANIM3 de Daniel Coulom pour THOMSON modifié pour le mode
# "2 octets"
#
#        (http://forum.system-cfg.com/viewtopic.php?p=104928#p104928)
#
# par Samuel Devulder.
#
# Historique:
# ===========
# 09/06/2015 - version initiale. Portage semi direct du code C.
#
# 10/06/2015 - utilisation de la matrice vac-8 qui donne une image plus 
#              fine que le h4x4a
#            - fps et zoom revu pour avoir une vitesse et une qualité 
#              très correcte (10fps et zoom 70%)
#            - optimisation de la vitesse de compression:
#                - les bords noirs supérieur et inférieurs de l'écran 
#                  sont ignores
#                - la boucle while cherchant les différences ne lit à
#                  présent qu'un seul des deux tablraux puisque la lecture 
#                  nous fournit en cible le delta avec l'image actuelle.
#              du coup la vitesse d'encodage passe de x0.4 à x1.
#            - meilleure synchro video quand une image est compressée en 
#              moins de BUFFSIZE octets: on retourne simplement en haut
#              de l'écran sans re-encoder la même image de sorte qu'au
#              changement d'écran on redémarre en haut de la nouvelle image. 
#              On ne voit quasiment plus des demi-images et la vidéo est
#              très fluide
#            - mise en place d'une correction sonnore auto-adaptative. 
#              Donne d'excellents resultats pour Dire Straits (sultan of
#              swing est fort et clair avec une bonne dynamique à présent).
#            - stockage des images temporaires dans un sous-dossier tmp/
#              pour ne opas polluer le répertoire courant.
#                  
# 12/06/2015 - mise en place d'un algo pour calculer le meilleur zoom
#              ou framerate. Dans un 1er temps la vidéo est échantillonnée
#              à 1 image /sec (pour aller vite) avec un zoom de 1. Puis
#              compressée sans limite de taille de buffer. A la fin de la 
#              vidéo on obtient le nombre d'octets moyen par image (LEN_BY_IMG). 
#
#              si LEN_BY_IMG est inférieur au BUFFERSIZE associé au framerate
#              choisi (FPS), ca veut dire que le framerate est un peu petit
#              et que l'on gaspille des octets puisque BUFFERSIZE n'est pas
#              complètement rempli. On peut alors augmenter le framerate de
#              la même proportion d'écart entre BUFFERSIZE et LEN_BY_IMG:
#                       FPS <- FPS*(BUFFERSIZE/LEN_BY_IMG)
#              C'est ce qu'il se passe avec les video facilement compressibles
#              l'outil va en profiter pour augmenter le FPS afin d'occuper
#              tout le buffer alloué à une image. Cependant le cas le plus
#              fréquent est le suivant:
#
#              Si LEN_BY_IMG est supérieur à BUFFERSIZE, c'est que ce dernier
#              est trop petit pour contenir une image compressée. On peut alors
#              jouer sur le facteur de zoom pour que l'image compressée tienne
#              dans BUFFERSIZE. En première approximation si on réduit l'image
#              d'un facteur r<1, le nombre de pixel à compresser est réduit
#              d'un facteur r*r. La taille compressée est elle aussi sensiblement
#              réduite du même facteur (imaginez diviser une image par 2, il y a
#              4x fois moins d'information à compresser, et la compression sera
#              aussi 4x plus petite). Du coup cela veut dire que r*r peut valoir
#              LEN_BY_IMG/BUFFERSIZE plus une petite marge (que je fixe à 15%).
#              Cela signifie que l'on peut utiliser un zoom de
#                       SQRT(BUFFERSIZE/(LEN_BY_IMG + 15%))
#              pour avoisiner le taux d'occupation idéal de BUFFERSIZE.
#
#            - mise en place d'un contraste sigmoidal qui tasse les intensités
#              sombre et lumineuses afin d'avoir des image très contrastée qui
#              apparaissent dès lors un peu moins bruitées. Cependant je 
#              les trouve alors moins riche au niveau des dégradés.
# 
# 27/06/2015 - Adapation au player "2octets", retour au ordered-dither,
#              detection du bon espace RGB linéaire.
#
# 30/06/2015 - Ajout d'un algo de re-normalisation des niveau RVB pour eviter
#              d'avoir un film globalement trop sombre. Le contraste et les
#              couleurs sont grandement amméliorés.
#
# 03/07/2015 - Adaptation au protocole "sans acquitement" permettant d'avoir
#              une bande passante video 3x par rapport à l'audio.
#
##############################################################################

$file = $ARGV[0];

# params par defaut
mkdir("tmp");
$img_pattern = "tmp/img%05d.bmp";
($w, $h) = (320, 180); # 16:9
$hz  = int(2000000/74)/2;
$fps = 10;
$interlace = 0; # 0=off, 1=simple, 2=smart
$coul = 0;
$audio_dither = 0;

$BUFFERSIZE = 7*int(($hz+$fps-1)/$fps);

# recherche la taille de l'image
($x,$y, $aspect_ratio) = (320,200,"16:9");
open(IN, "./ffmpeg -i \"$file\" 2>&1 |");
while(<IN>) {
	if(/, (\d+)x(\d+)/) {
		($x,$y) = ($1, $2);
		# 4:3
		if(abs($x - 4/3*$y) < abs($x - 16/9*$y)) {
			($w,$h,$aspect_ratio) = (266,200,"4:3");
		}
	}
}
close(IN);
$h = int(($w=320)*$y/$x);
$w = int(($h=200)*$x/$y) if $h>200;

print $file," : ${x}x${y} ($aspect_ratio) -> ${w}x${h}\n";

# AUDIO: unsigned 8bits, mono, 16125hz
open(AUDIO, "./ffmpeg -i \"$file\" -v 0 -f u8 -ac 1 -ar ".int(2*$hz)." -acodec pcm_u8 - |");
binmode(AUDIO);

# tuyau vers ffmpeg pour images
open(FFMPEG,'| (read line; $line)');#  -vf format=gray
binmode(FFMPEG);

# fichier video (entree)
open(IN, "<$file");
binmode(IN);

# determination du zoom optimal
$zoom = &guess_zoom($w, $h);
$fps = int($fps * ($zoom>1?$zoom:1));
$BUFFERSIZE = 7*int(($hz+$fps-1)/$fps);
$w = int($w*($zoom>1?1:$zoom));
$h = int($h*($zoom>1?1:$zoom));
print sprintf("zoom = %.2g -> %dx%d @ %dfps\n", $zoom, $w, $h, $fps);
$cmd = "./ffmpeg -i - -v 0 -r $fps -s ${w}x${h} -an $img_pattern\n";
syswrite(FFMPEG, $cmd, length($cmd));

# nettoyage
unlink(<tmp/img*.bmp>);

# fichier sd (sortie)
$name = $file; $name =~ s/\.[^\.]*$//; $name .= ".sd";
open(OUT, ">$name");
binmode(OUT);

# multiplicateur audio
@audio_cor = (8, 255);

# compteur image
$cpt = 1;

# ecran courant
@ecran = ((0) x 8000);

# position dans ecran
$pos = 8000;

# compression
$time = 0; $start = time; $realimg = 0; $pause = 60;
while(&next_image(*IN,*FFMPEG,$w,$h) && &compresse()) {
	if($cpt%$fps == 0) {
		++$time;
		my($d) = time-$start+.0001;
		print STDERR sprintf("%d:%02d:%02d (%.2gx) v=1:%.3g a=(x%+d)*%.1g        \r",
			int($time/3600), int($time/60)%60, $time%60,
			int(100*$time/$d)/100, $realimg/($cpt-1), -$audio_cor[1], $audio_cor[0]);
		# pour ne pas trop chauffer
		if($d>$pause) {
			$pause = $d+60;
			sleep(10);
		}
	}
	
	#last if $time>30;
}

# fin fichier
print OUT pack('C*', (0x00,0x00,0x00) x int(1+$BUFFERSIZE/7));

# nettoyage et fermetue flux
print STDERR "\n";
unlink(<tmp/img*.bmp>);
close(OUT);
close(IN);
close(FFMPEG);
close(AUDIO);

# Lit l'image suivante. Retourne 1 si ok, 0 si fin fichier
sub next_image {
	my($IN, $OUT, $w, $h) = @_;
	# nom du fichier BMP
	my $name = sprintf($img_pattern, $cpt++);
	
	# taille fichier BMP
	my $expected_size = $h*(($w*3 + 3)&~3) + 54; # couleur

	#print "$w, $h, $expected_size\n";

	# on nourrit ffmpeg jusqu'a obtenir un fichier BMP fini
	while($expected_size != -s $name) {
		my $buf;
		my $read = read($IN,$buf,8192);
		last unless $read;
		syswrite $OUT, $buf, $read;
	} 
	
	# chargement image-magick la 1ere fois
	if(!$_magick) {
		$_magick = 1;
		
		my($home) = "tmp";
		$ENV{'HOME'} = $home;
		mkdir($home);
		mkdir("$home/.magick");
		open(THR, ">$home/.magick/thresholds.xml");
		
		if($coul) {
			print THR <<EOF1;
		<thresholds>
			<threshold map="sd">
                                <description>void and cluster 28 niveaux pour couleur</description>
                                <levels width="9" height="9" divisor="28">
					24 2 16 11 25 5 19 7 18
					11 25 5 19 7 18 24 2 16
					6 24 18 7 19 1 25 11 16
					10 14 26 3 17 9 23 15 4
					3 17 9 23 15 4 10 14 26
					2 21 12 26 5 13 22 8 20
					21 6 20 8 22 13 1 27 12
					8 22 13 1 27 12 21 6 20
					14 10 3 15 23 9 17 4 27
				</levels>
			</threshold>
		</thresholds>
EOF1
		} else {
			print THR <<EOF2;
		<thresholds>
			<threshold map="sd">
				<description>void and cluster 65 niveaux</description>
				<levels width="8" height="8" divisor="65">
					35 57 19 55 7 51 4 21
					29 6 41 27 37 17 59 45
					61 15 53 12 62 25 33 9
					23 39 31 49 2 47 13 43
					3 52 8 22 36 58 20 56
					38 18 60 46 30 5 42 28
					63 26 34 11 64 16 54 10
					14 48 1 44 24 40 32 50
				</levels>
			</threshold>
		</thresholds>
EOF2
		}		
		close(THR);
		
		eval 'use Image::Magick;';
		# determination de l'espace RGB lineaire
		my $img = Image::Magick->new(size=>"256x1", depth=>16);
		$img->Read('gradient:black-white');
		$img->Set(colorspace=>'RGB');
		#$img->Set(colorspace=>"Gray") unless $coul;
		my @px1 = $img->GetPixel(x=>128, y=>0);
		$img->Read('gradient:black-white');
		$img->Set(colorspace=>'sRGB');
		#$img->Set(colorspace=>"Gray") unless $coul;
		my @px2 = $img->GetPixel(x=>128, y=>0);
		my $d1 = $px1[0]-0.5; $d1=-$d1 if $d1<0;
		my $d2 = $px2[0]-0.5; $d2=-$d2 if $d2<0;
		$LINEAR_SPACE = $d1>=$d2 ? "RGB" : "sRGB";
		#print $px1[0], "   ",$px2[0],"    $LINEAR_SPACE\n";
	}
	
	# lecture image
	my $tmp = Image::Magick->new();
	my $z = $tmp->Read($name);
	#print STDERR $z if $z;
	return 0 if $z; # si erreur => fin fichier
	unlink $name;
	

	# dither
	$tmp->Set(depth=>16);
	$tmp->Set(colorspace=>$LINEAR_SPACE);
	$tmp->Set(dither=>"FloydSteinberg");

	if($phase==1) {
		@stat = (0)x256 unless $#stat>=0;
		my(@p) = $tmp->GetPixels(map=>"RGB", height=>$h, width=>$w, normalize=>"True");
		for my $p (@p) {++$stat[int(255*$p)];}
	} 
	if($phase==2) {
		my $tot = -$stat[0];
		for my $p (@stat) {$tot += $p;}

		my $thr = $tot*5/100;
		$lvl_max=$#stat;
		for(my $t=0; ($t+=$stat[$lvl_max])<$thr;  --$lvl_max) {}
		$lvl_min=0;$thr/=2;
		for(my $t=0; ($t+=$stat[$lvl_min])<$thr;  ++$lvl_min) {}
		print "re-level: $lvl_min->0 $lvl_max->255\n";
		$phase = $lvl_max>0 && $lvl_max<255 ? 3 : 4;
	} 
	if($phase==3) {
		#$tmp->Evaluate(operator=>'Subtract', value=>$lvl_min/255);
		#$tmp->Evaluate(operator=>'Multiply', value=>255/($lvl_max-$lvl_min));
		$tmp->Evaluate(operator=>'Multiply', value=>255/$lvl_max);
	}
	# $phase==4 rien
	
	
	if(0) {
		#$tmp->Set(monochrome=>"True");
		if(!$bw_img) {
			$bw_img = Image::Magick->new(size=>"2x1");
			$bw_img->Read("pattern:gray50");
		}
		$tmp->Set(colorspace=>"gray");
		$tmp->Remap(image=>$bw_img, dither=>"True", "dither-method"=>"FloydSteinberg");
	} elsif(!$coul) {
		# mieux ?
		$tmp->Set(colorspace=>"gray");
		#$tmp->OrderedDither(threshold=>"o8x8,2");
		#$tmp->OrderedDither(threshold=>"h8x8a,2");
		$tmp->OrderedDither(threshold=>"sd,2");
	} else {
		#$tmp->Gamma(gamma=>1.6);
		$tmp->OrderedDither(threshold=>"sd,2");
	}
	
	# centrage dans image 320x20
	my $img = Image::Magick->new(size=>"320x200");
	$img->Read("canvas:black");
	$img->Composite(image=>$tmp,compose=>"Over",
	                x=>(320-$w)>>1,y=>(200-$h)>>1);
			
	my($start) = (200-$h)>>1;
	$img->Draw(stroke=>"White", primitive=>"line", points=>"0,$start ".int(319*($cpt-1)/($fps*$total_sec)).",$start") if defined($total_sec);
	
	# remplissage variable globale @cible
	my(@p) = $img->GetPixels(map=>"RGB", height=>200, width=>320, normalize=>"True");
	
	
	
	
	my($stop)  = (200-$start)*960-3;
	
	@cible = (0)x(40*$start);
	if(!$coul) {
		for(my $i=$start*960-3; $i<$stop;) {
			my $v = 0;
			for my $j (0..7) {$v <<= 1; $v |= 1 if $p[$i+=3]>.5;}
			push(@cible, $v ^ $ecran[1+$#cible]);		
		}
	} else {
		for my $y ($start..(199-$start)) {
			my $i = $y*960 - 3 + ($y%3);
			for my $x (0..39) {
				my $v = 0;
				for my $j (0..7) {$v <<= 1; $v |= 1 if $p[$i+=3]>.5;}
				push(@cible, $v ^ $ecran[1+$#cible]);		
			}
		}
	}
	push(@cible, (0)x(40*$start), 1);
	
	my $f = sub {
		my($y) = @_;
		splice(@cible, $y*40, 40, (0)x40);
	};
	$f = sub {
		my($y) = @_;
		
		if(!@cnt) {
			for my $i (0..255) {
				$cnt[$i] = 0;
				my $t = $i;
				while($t) {++$cnt[$i]; $t ^= $t&-$t;}
			}
		}
		$y *= 40; my($c) = 0;
		for my $i ($y..$y+39) {$c += $cnt[$cible[$i]];}
		splice(@cible, $y, 40, (0)x40) if $c<40*$w/320;
	} if $interlace==2;
	
	if($interlace && !$coul) {
		for(my $y=$cpt&1; $y<200; $y+=2) {$f->($y);}
	}	
	if($interlace && $coul && ($cpt&1)) {
		for(my $y=1; $y<200; $y+=3) {$f->($y);}
	}
	if($interlace && $coul && !($cpt&1)) {
		for(my $y=0; $y<200; $y+=3) {$f->($y);}
		for(my $y=2; $y<200; $y+=3) {$f->($y);}
	}
	
	return 1;
}

# compresse @cible dans $BUFFERSIZE
sub compresse {
	my(@buf) = (0)x$BUFFERSIZE;
	my($ok) = 1;
	my($k);
	my($img_complete) = 0;
	
	# video
	my($i) = 0;
	if($pos>=8000) {
		$buf[$i+0] = $pos = 0;
		$buf[$i+1] = ($ecran[$pos] ^= $cible[$pos]); $cible[$pos]=0;
		$i += 2; 
	}
	while($i < $BUFFERSIZE) {
		my $p = $pos % 8000;
		my($k) = 1;
		while($k<255 && !$cible[$p+$k]) {++$k;}
		$pos+=$k;
		$k = $p = 0 if ($p+=$k)==8000;
		$buf[$i+0] = $k;
		$buf[$i+1] = ($ecran[$p] ^= $cible[$p]); $cible[$p]=0;
		#01 23 45 6 78 90 12 3 45 67 89 0 12 34 56 7 89 01 23 4 56 78 90 1
		$i+=2; ++$i if ($i % 7)==6;
	}
	++$realimg if $pos>=8000;
	
	# audio
	for(my $i=6; $i<$BUFFERSIZE; $i+=7) {
		if(!@AUDIO) {
			my($buf);
			if(!read(AUDIO,$buf,8192)) {
				$buf[$i+2] = 0xff; # EOF
				$ok = 0;
				last
			}
			push(@AUDIO, unpack('C*', $buf));
		}
		my $v = (shift(@AUDIO)+shift(@AUDIO))/2;
		# volume auto
		$audio_cor[1] = $v if $v<$audio_cor[1];
		$v-=$audio_cor[1];
		$audio_cor[0] = 255/$v if $v*$audio_cor[0]>255;
		$v *= $audio_cor[0];
		# dither audio
		$v += int(rand(3)) if $audio_dither; 
		$v=255 if $v>255;
		$buf[$i] = ($v>>2) | 0x80 | (($i % 14)==6?0x40:0x00);
	}
	
	# write
	print OUT pack('C*', @buf);
	
	return $ok;
}

sub guess_zoom {
	my($w, $h) = @_;
	
	# tuyau vers ffmpeg pour images
	open(GOUT,"| ./ffmpeg -i - -v 0 -r 1 -s ${w}x${h} -an $img_pattern");#  -vf format=gray
	binmode(GOUT);

	# fichier video (entree)
	open(GIN, "<$file");
	binmode(GIN);
	unlink(<tmp/img*.bmp>);
	
	@ecran = ((0)x8000, 1);
	local $cpt = 1;
	my $size = 1;
	$phase = 1;
	while(&next_image(\*GIN, \*GOUT,$w,$h)) {
		my $p = 0;
		while($p<8000) {
			my $k = 1;
			while($k<255 && !$cible[$p+$k]) {++$k;}
			$p+=$k; 
			$size += 2; ++$size if ($size%7)==6;
		}
		$size += 2; ++$size if ($size%7)==6;
		for $p (0..7999) {$ecran[$p] ^= $cible[$p];}
		print STDERR sprintf("avg %dx%d frame length = %d bytes (%d%%) @ %ds                 \r", $w, $h, int($size/($cpt-1)), int(100*$size/(($cpt-1)*$BUFFERSIZE)), $cpt-1);
	}
	$phase = 2;
	
	$total_sec = $cpt-1;
	unlink(<tmp/img*.bmp>);
	print STDERR "\n";
	my $len_per_img = ($size/($cpt-1)) * (1.20); # 20% extra
	close(GIN);
	close(GOUT);
	my $zoom = $BUFFERSIZE/$len_per_img;
	return $zoom>=1?$zoom:sqrt($zoom);
}
En fait ca pourrait marcher à 50fps, mais les 20% d'extra que j'ajoute à la moyenne font descendre à 40 et quelques. Bon par contre comme l'encodeur a plus d'images à traiter (4 à 5x plus), il encode très lentement: 1 pour 10 (1sec de vidéo prend 10secs. Un film de 2h20 prendrait quasiment la journée). J'ai aussi fait passer le taux de pixels sur-exposés de 4 à 5% "pour voir". On perd beaucoup de couleur qui sont toutes tirées vers le blanc.
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 : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Vidéo avec son en streaming

Message par __sam__ »

a tester: les autres vidéo. Seront-elle aussi rapides? Je ne pense pas: indiana-jones a beaucoup de noir qui se compresse bien..
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 : 17408
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Vidéo avec son en streaming

Message par Daniel »

Nouvelle version de dcmoto avec une case à cocher "Interface Arduino". C'est plus naturel que de cocher Interface SDMOTO :wink:
http://dcmoto.free.fr/emulateur/dcmoto_nouveau.zip

Avec le nouveau protocole de transmission, le film est fluide sans réduction de taille de l'écran. C'est, je crois, la vitesse maximum possible avec un 6809 à 1MHz pour lire des données. On lit le support de masse à la même vitesse que la RAM. Comme si on avait une RAM de 32Go sur le MO5, mieux que beaucoup de PC actuels (sauf que l'accès est uniquement séquentiel).

Techniquement, je ne vois plus de progrès possible pour la vitesse. Reste maintenant à faire fonctionner le programme sur le vrai matériel : c'est uniquement une question de temporisations dans le sketch Arduino. Plutôt que de tenter ma chance par approximations successives, je vais écrire des programmes de test pour déterminer le nombre de cycles consommés par chaque routine. Quand je connaîtrai exactement les timings il sera plus facile d'ajouter les temporisations. Il existe dans la bibliothèque de l'Arduino une fonction delayMicroseconds(x), mais d'après la doc elle n'est juste que pour des valeurs élevées de x. Dans notre cas ça se joue à la microseconde près, il va falloir ruser...

Un petit détail : dans le programme Basic, les lignes de couleur sont longues à afficher, le début du film se fait attendre, c'est un suspens insoutenable. Déplacer le traitement dans le programme assembleur diminuerait l'attente :wink:
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Vidéo avec son en streaming

Message par __sam__ »

Daniel a écrit :Techniquement, je ne vois plus de progrès possible pour la vitesse.
Il y a une possibilité à laquelle je réfléchis car l'encodage offset+donnée-vidéo est très peu économe sur les gros changements où offset constant à 1 mange la moitié de la bande passante sans fournir d'info nouvelles. La dessus l'encodage "2octets" était pas mal. En fait je pense que l'encodage 2octets pourrait rester mais dans une forme n-octets (n à bien déterminer: trop gros il ne sera pas utilisé). Le truc c'est qu'on perd l'oscillation du B6 fournie par le stream lui même. Ici il y a quelques possibilités:
1) tant pis, on fait l'oscillation logiciellement avec un XORA #$40. Ca ne fait perdre que quelques cycles.
2) on laisse B6 tranquile mais on utilise B7 qui est largement sous-exploité (tout le temps fixe). Je pense là à ne tester le B7 que lors du dernier retour écran.
3) un mélange des deux.

J'ai pas les idées claires, mais je pense qu'on peut aller un peu au dessus du débit effectif actuel quand l'offset n'est que de 1. Peut être faut il prendre un encodage encore plus malin capable de recopier n octets d'affilés en mémoire vidéo. Les sauts ne se faisant que de façon exceptionnelle pour passer d'une ligne à la suivante ou vers le retour écran.

Bon pour le moment c'est très vague, et on ne sait pas si l'absence de synchro à chaque échange est viable sur du vrai matériel.

Pour les couleurs en asm, c'est possible mais le hic c'est que l'encodage couleur est différent entre MO et TO. Cela peut se traiter, mais un truc qu'il serait possible dans ce cas, c'est de réserver le 1er octet du stream pour dire le type d'encodage couleur: N&B, MOD3, AND3, etc.
[EDIT] autre avantage: ce 1er octet pourrait être lu avec le protocole lecture/écriture ce qui permet d'indiquer à l'arduino un top départ de référence pour la synchro.
Dernière modification par __sam__ le 04 juil. 2015 17:07, modifié 1 fois.
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 : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

vec

Message par __sam__ »

__sam__ a écrit :J'ai pas les idées claires, mais je pense qu'on peut aller un peu au dessus du débit effectif actuel quand l'offset n'est que de 1. Peut être faut il (...)
J'ai réflechi. Tout est clair et très simple (ce qui est bon signe). Toujours en gardant le format 1 octet son pour 6 octets vidéo je suis arrivé à l'encodage suivant:

Code : Tout sélectionner

decal1 video1 video2 decal2 video3 video4 son
Bon on voit que là où avant on avait 3 octets vidéo, on en a maintenant 4 ce qui augmente la bande passante vidéo. Par contre il n'y a plus que 2 décalages ce qui n'est pas suffisant pour 4 octets vidéo. Sauf que à présent les écrits 2 par 2 avec une écriture 16 bits (STD: 5 cycles) qui est bien plus rapide que deux écriture de deux octets individuels (8 cycles). En gros l'octet video est transformé en mot 16bits video. C'est tout simple, mais par contre on lit le port A un peu rapidement, mais j'y reviendrais plus loin. Cela donne le player suivant

Code : Tout sélectionner

10 CLEAR,&H8FFF
20 COLOR7,0:SCREEN,,0:CLS:LOCATE0,0,0
25 CONSOLE,,0:FORI=0TO199:LINE(0,I)-(319,I),2^(I MOD3):NEXT:CONSOLE,,1:CLS
30 READ A$:IF LEN(A$)=4 THEN A=VAL("&H"+A$):GOTO 30
40 IF A$="**" THEN EXEC A ELSE POKE A,VAL("&H"+A$):A=A+1:GOTO 30
50 DATA 9000
60 DATA 34,7F,1A,50,8E,1F,40,E6,84,63
70 DATA 84,E1,84,27,0A,63,84,CE,A7,C0
80 DATA 8E,00,00,20,06,CE,E7,C3,8E,40
90 DATA 00,BF,90,45,BF,90,57,A6,C4,8A
100 DATA 01,A7,C4,1F,30,1F,8B,4F,5F,DD
110 DATA CE,C6,7F,DD,CC,8A,04,97,CE,97
120 DATA CF,D6,CC,27,03,3A,20,05,8E,40
130 DATA 00,20,00,96,CC,D6,CC,ED,84,D6
140 DATA CC,27,03,3A,20,05,8E,40,00,20
150 DATA 00,96,CC,D6,CC,ED,84,96,CC,97
160 DATA CD,2B,D6,35,FF
170 DATA 9000,**
-------------------8<------------------------------------------------------------
(main)sdplay2
  ORG   $9000
INI
  PSHS  U,Y,X,DP,B,A,CC  empile les registres
  ORCC  #$50      masque les interruptions
  LDX   #$1F40    adresse pour test RAM ou ROM
  LDB   ,X        lecture adresse X
  COM   ,X        tente de modifier adresse X
  CMPB  ,X        test modification adresse X
  BEQ   INIT1     pas de difference -> TO
  COM   ,X        retablissement adresse X
  LDU   #$A7C0    port A du PIA systeme
  LDX   #$0000    adresse dans ecran
  BRA   INIT2     suite des initialisations   
INIT1
  LDU   #$E7C3    port A du PIA systeme
  LDX   #$4000    adresse dans ecran
INIT2
  STX   NEWPICa+1 adresse debut ecran
  STX   NEWPICb+1 adresse debut ecran
  LDA   ,U        port A du PIA systeme
  ORA   #1        set bit 0
  STA   ,U        passage en video forme
  TFR   U,D       extraction base $E7/$A7
  TFR   A,DP      initialisation DP
  CLRA            A=$00
  CLRB            B=$00
  STD   <$CE      selectionne DDRA et DDRB
  LDB   #$7F      B=$7F
  STD   <$CC      PA b0-7 en entree, PB b0-6 en sortie
  ORA   #$04      set b2
  STA   <$CE      selectionne PORTA
  STA   <$CF      selectionne PORTB
 
*------------------------------------------------------
* JOUE LA VIDEO ET LA MUSIQUE
* Boucle de 63 cycles = 15873.01 Hz
*------------------------------------------------------

START

PLAY macro
  
* lecture octet depl = 13 cycles
  LDB   <$CC      (4) lecture octet deplacement
  BEQ   NEWPIC\0  (3) nouvelle image
  ABX             (3) ajout de l'increment
  BRA   PLAY3\0   (3) octet video
 
* retour debut ecran = 6 cycle
NEWPIC\0
  LDX  #$4000     (3) retour debut ecran
  BRA  PLAY3\0    (3) poursuite image
   
* sortie video = 13 cycles
PLAY3\0
  LDA   <$CC      (4) lecture octet image
  LDB   <$CC      (4) lecture octet image
  STD   ,X        (5) affiche l'octet image 
  endm
 
  PLAY a          (26) triplet video
  PLAY b          (26) triplet video
 
* echantillon son (8 cycles)
  LDA   <$CC      (4) lecture echantillon son avec B6 alternant
  STA   <$CD      (4) joue le son et acknowledge   

* sortie ?
  BMI   START     (3)
 
*------------------------------------------------------
* RETOUR AU BASIC
*------------------------------------------------------
 
* retour au Basic
  PULS CC,A,B,DP,X,Y,U,PC 
  
* retour a l'assembleur
*  SWI
  
  END INI
qui tourne en 63 cycles par bloc de 7 octets, soit une fréquence audio de 15873.01 Hz. Notez que c'est quasiment un entier et qu'il est très proche du player initial de Daniel.

Avec lui indiana-jones tourne à 57 images par secondes: http://www.cjoint.com/doc/15_07/EGeocax ... r-Scene.7z

Je crois que là on est tout proche de l'optimum et que la bande passante disponible est utilisée au mieux... et même trop bien, car il y a deux lectures consécutives de <$CC, ce qui va poser des problèmes de timing du coté de l'arduino.

Est-ce donc un player fictif qui ne marchera que sur émulateur et jamais dans la pratique? :?

Et bien je pense que non. :D Car si j'organise le bloc de 7 octets ainsi

Code : Tout sélectionner

video1 decal1 video2 video3 decal2 video4 son
je pense que l'entrelacement des accès à <$CC permettra a l'arduino d'avoir des temps d'attente plus longs que la µs. Il faut que j'y travaille, mais ca me semble tout à fait possible.

A ton avis Daniel, quel est la durée d'attente mini fiable pour l'arduino en µs ? 2, 10 ?
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 : 17408
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Vidéo avec son en streaming

Message par Daniel »

Pour éviter les attentes au changement de bloc, je m'oriente vers un algorithme où l'Arduino lit plus d'octets de la carte SD qu'il en envoie sur le port de sortie. Par exemple, pour 8 octets envoyés, on en lirait 10 ou 12, pour constituer une réserve à jouer pendant l'inter-bloc. Ce qui veut dire qu'entre deux envois on peut lire zéro, un ou deux octets de la carte SD. On peut donc avoir un délai très court entre certains octets (en ne lisant aucun octet sur la carte SD à ce moment là), à condition d'avoir le temps d'en lire deux à d'autres moments. C'est assez souple, et je suis assez confiant. Il reste à évaluer le temps de lecture d'un octet par l'Arduino, je vais le faire dans les prochains jours.

Finalement, la lecture du fichier .sd par le 6809 est peut-être plus rapide que la lecture de la RAM, car il n'y a pas d'index à incrémenter. La mémoire de masse plus rapide que la RAM, c'est un paradoxe intéressant :wink: L'Arduino a une horloge à 16 MHz et les instructions utilisent très peu de cycles : un délai inférieur à la microseconde entre deux octets ne me surprendrait pas. Mais en fait je n'en sais rien, car l'écriture vers le port de sortie n'est peut-être pas une simple instruction. Reste à vérifier.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Vidéo avec son en streaming

Message par __sam__ »

Bon, finalement j'ai modifié le code du player et n'ai plus besoin de réorganiser les blocs, ce qui m'arrange parce que j'ai déjà encodé quelques clips:

Code : Tout sélectionner

$ for i in *.flv *.mp4; do echo; nice -19 perl conv_sd4.pl "$i"; done

Bigfoot caught on tape (Patterson footage stabilized).flv : 320x240 (4:3) -> 266x200
avg 266x200 frame length = 8597 bytes (77%) @ 109s
zoom = 1.2 -> 266x200 @ 11fps
re-level: 0->0 226->255
0:01:48 (0.26x) v=1:0.997 a=(x-107)*6

Custom Knight rider intro 1 - Classic.flv : 320x240 (4:3) -> 266x200
avg 266x200 frame length = 4307 bytes (38%) @ 75s
zoom = 2.4 -> 266x200 @ 23fps
re-level: 0->0 153->255
0:01:13 (0.13x) v=1:0.973 a=(x-47)*2

David Guetta - Dangerous (Official video) ft Sam Martin.flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 9312 bytes (83%) @ 429s
zoom = 1.1 -> 320x180 @ 10fps
re-level: 0->0 255->255
0:07:08 (0.25x) v=1:0.963 a=(x-2)*1

Dire Straits - Money For Nothing.flv : 320x240 (4:3) -> 266x200
avg 266x200 frame length = 5262 bytes (47%) @ 302s
zoom = 1.9 -> 266x200 @ 19fps
re-level: 1->0 106->255
0:04:59 (0.16x) v=1:0.952 a=(x-76)*2

Dire Straits - Sultans Of Swing.flv : 320x240 (4:3) -> 266x200
avg 266x200 frame length = 5191 bytes (46%) @ 268s
zoom = 2 -> 266x200 @ 19fps
re-level: 0->0 178->255
0:04:26 (0.17x) v=1:0.964 a=(x-102)*5

Georges Brassens Bobino 1972 08 Les amours d'antan.flv : 318x240 (4:3) -> 265x200
avg 265x200 frame length = 4155 bytes (37%) @ 198s
zoom = 2.4 -> 265x200 @ 24fps
re-level: 0->0 128->255
0:03:17 (0.13x) v=1:0.995 a=(x-4)*1

Geri Halliwell - It's Raining Men.flv : 326x240 (4:3) -> 271x200
avg 271x200 frame length = 7748 bytes (69%) @ 308s
zoom = 1.3 -> 271x200 @ 13fps
re-level: 0->0 255->255
0:05:07 (0.24x) v=1:0.961 a=(x-72)*2

Gotan Project - De Hombre a Hombre.flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 2896 bytes (26%) @ 230s
zoom = 3.5 -> 320x180 @ 35fps
re-level: 0->0 120->255
0:03:34 (0.1x) v=1:0.939 a=(x-5)*1

Gotan Project - Diferente (Official music video).flv : 320x240 (4:3) -> 266x200
avg 266x200 frame length = 4231 bytes (38%) @ 215s
zoom = 2.4 -> 266x200 @ 23fps
re-level: 0->0 175->255
0:03:33 (0.13x) v=1:0.979 a=(x-101)*5

Gotan Project - Santa Maria (Del Buen Ayre) (HD).flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 1934 bytes (17%) @ 207s
zoom = 5.3 -> 320x180 @ 52fps
re-level: 0->0 63->255
0:02:13 (0.07x) v=1:0.91 a=(x-94)*4
Toutes sont plein écran et font souvent plus de 20fps. A ces vitesses là les vidéos sont très très fluides, c'est impressionnant. Dommage que les couleurs ne sont pas aussi brillantes à cause de la répartition sur 3 lignes.

Les temps entre 2 lectures sur le port A sont les suivants (en cycle 6809, cad en µs): 6 3 5 6 3 5 7 (6 3 5 6 3 5 7 ...). C'est faisable selon toi ? 3µs me semblent très courts, mais il faurait peut être intégrer le temps effectif de lecture du port A (4 cycles), ce qui nous donne: 10 7 9 10 7 9 11. 7µs ca devrait pouvoir se faire.
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 : 17408
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Vidéo avec son en streaming

Message par Daniel »

Les premiers tests de vitesse de l'Arduino en lecture de la carte SD et écriture sur le port D donnent 2µs par octet.

J'ai lu un fichier de 100 millions d'octets en 201,8 secondes.
Pour chaque bloc de 512 il y a en plus un octet de début de bloc, deux octets de CRC et deux ou trois octets inter-blocs, soit au moins un millions d'octets de plus à lire. Finalement le changement de bloc ne dure pas plus d'une douzaine de microsecondes.

Dans ce test, je ne sais pas quelle est la durée de traitement des boucles while(), mais je la suppose négligeable par rapport à la lecture d'un octet en mode SPI. Si ce n'était pas le cas, on pourrait dérouler la boucle de 512 et la boucle d'attente de l'octet 0xfe.

Ci-dessous la boucle de lecture de l'Arduino :

Code : Tout sélectionner

 nbloc = (AudioFileInfo.Size / 512) + 1;

 while(nbloc-- > 0)      // tant qu'il reste des blocs a lire
 {
  //attendre l'octet 0xfe de debut de bloc
  c = 0;
  while(c != 0xfe)
  {
   SPDR = 0xff;
   while(!(SPSR & (1 << SPIF)));
   SPSR &= ~(1 << SPIF);
   c = SPDR;
  }

  // lire et jouer 512 octets du bloc
  i = 512;
  while(i-- > 0)
  {
   //lecture d'un octet
   SPDR = 0xff;
   while(!(SPSR & (1 << SPIF)));
   SPSR &= ~(1 << SPIF);
   PORTD = SPDR; //write byte to output port
  }
  
  //ignorer les deux octets de CRC
  SPDR = 0xff;
  while(!(SPSR & (1 << SPIF)));
  SPSR &= ~(1 << SPIF);
  SPDR = 0xff;
  while(!(SPSR & (1 << SPIF)));
  SPSR &= ~(1 << SPIF);
 }
Dans l'enchaînement LDA <$CC, LDB <$CC, je ne sais pas exactement combien de cycles sont disponibles entre les deux accès à <$CC. Si c'est plus de deux, on devrait avoir le temps de lire un octet sur la carte, mais la marge d'erreur dans le timing est très étroite. Par contre, avec les délais de 9, 10 et 11 µs, on peut lire sans problème deux ou trois octets sur la carte. Tout ça est théorique, reste à voir si ça marche en pratique. Ce n'est pas gagné d'avance.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Vidéo avec son en streaming

Message par __sam__ »

Daniel a écrit :Tout ça est théorique, reste à voir si ça marche en pratique. Ce n'est pas gagné d'avance.
C'est ca qui est passionnant: confronter la théorie avec la pratique. Si ca ne marche pas on peut toujours rebasculer sur une solution avec acquittement par front. Ca donnerait une vitesse intermédaire entre le mode "2 octets" et le mode "4 octets-video + son".
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 : 17408
Inscription : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

Re: [Thomson] Vidéo avec son en streaming

Message par Daniel »

Si le fichier .sd est organisé par blocs de 512 octets, le traitement sur l'Arduino est plus simple. Il faudrait aussi mettre l'octet son en tête pour permettre la synchronisation en début de bloc, et prévoir une temporisation de 10 ou 12 µs après chaque bloc de 512.
Par exemple : 73 x (son + déplacement + vidéo + vidéo + déplacement + vidéo + vidéo) + 1 octet de remplissage par bloc de 512.

Si c'est possible pour toi, je vais partir sur ces bases. J'ajusterai les temporisations quand le player définitif sera écrit.
Daniel
L'obstacle augmente mon ardeur.
__sam__
Messages : 7964
Inscription : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

Re: [Thomson] Vidéo avec son en streaming

Message par __sam__ »

Plutôt que l'octet son en tête, je pense que le 1er octet "type"-son pourrait apporter l'info sur le type de fichier: couleur / n&b. C'est de l'administratif dont le contenu pourrait être enrichi avec le temps (par exemple si le format audio-video qui suit passe du format triplet déplacement-donnée à un doublet comme initialement, chaque bloc de 512 pouvant avoir un codage différent; ou encore indiquer le passage en mode video fond). Je propose que l'octet de bourrage soit utilisé pour ca dans chaque bloc 512.

admin/top-synchro + 73 x (dep1 + video1 + video2 + dep2 + video3 + video4 + son/synchro) = 512 octets

Ca semble pas mal comme ca en effet. Reste que ca revient à dérouler 73 fois la boucle de lecture. Le code ASM va grossir. C'est pas dramatique. Si je comprends bien il faut prévoir un temps d'attente à la fin des 512 octets lus. Est-ce qu'un saut à KTST peut s'y glisser histoire de prévoir une sortie prématurée de la lecture?

Par ailleurs je tombe sur 2 points ennuyeux:

1) la saturation à 4% est bien trop forte sur bon nombre de sections de certaines vidéos. (Harder Better Stronger de Daftpunk fait mal aux yeux tellement il est trop saturé). J'essaye de trouver une valeur moins brutale.
[EDIT] c'est corrigé: c'était un bug dans ma nouvelle matrice (je faisais des essais voyant que 1+15*17=256 qui est pile le niveau d'intensité par composantes RGB sur PC)

2) il y a un décalage du son sur les films longs au bout de 15-20mins et il me semble qu'il s'empire avec le temps. Je pense que l'accumulation des erreurs d'arrondi dans la frequence audio par rapport à la fréquence video. 1 échantillon audio d'écart toute les 2 images, c'est faible (erreur d'arrondi), mais au bout de 20mins à 50fps, ca nous fait 60 000 échantillons d'écart, qui à 15khz font 1.89 secs. C'est énorme, sachant qu'un retard de 0.2-0.5 sec sur l'audio se voit (le lèvres ne sont plus synchro).

Je n'ai pas de solution simple pour éviter ce décalage. Probablement qu'il faudrait de temps en temps lire un échantillon audio de plus pour mieux synchroniser les deux flux.
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
jester
Messages : 2328
Inscription : 01 janv. 2009 23:16
Localisation : Grenoble

Re: [Thomson] Vidéo avec son en streaming

Message par jester »

Mais qui regardera 20mn de vidéo en streaming sur Thomson ?
C'est génial pour insérer des vidéos courtes dans une démo, faire tendance dans une visu... s'éclater dans le développement et repousser les limites... mais factuellement personne au monde (à par les développeurs pour tester et par fierté) ne regardera 10mn de vidéo sur cette plateforme.
Ce n'est donc pas un gros problème ce décalage... même si je suis sur que vous allez le résoudre :?
Répondre