[Thomson] Vidéo avec son en streaming

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 : Carl, Papy.G, fneck

Répondre
__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 28 juin 2015 15:58

__sam__ a écrit :Demain je vais publier des exemples de ce que j'obtiens avec ce nouveau codage.... suspens.....
Petite modif.. le player précédent a une période de 65cycles, ce qui nous fait une fréquence en Hz qui ne tombe pas trop juste: 15384.6153846Hz. Pour avoir une fréquence en Hz plus agréable à utiliser j'ai écrit une version à 66cycles:

Code : Tout sélectionner

  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   NEWPIC+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
 
  BRA   PLAY1
 
*------------------------------------------------------
* JOUE LA VIDEO ET LA MUSIQUE
* Boucle de 66 cycles = 15151.51 Hz
*------------------------------------------------------
 
* lecture octet depl = 20 cycles
PLAY2
  ANDA  #$3F      (2) clear bit 6
  STA   <$CD      (4) acknowledge
  LDB   <$CC      (4) lecture octet deplacement
  BEQ   NEWPIC    (3) nouvelle image
  ABX             (3) ajout de l'increment
  JMP   PLAY3     (4) octet video
 
* retour debut ecran = 7 cycle
NEWPIC
  LDX  #$4000     (3)
  JMP  PLAY3      (4)
  
* mode 2 octets: 20+3 cycles
PLAY4
  ANDA  #$3F      (2) clear bit 6
  STA   <$CD      (4) request to send
  LDB   <$CC      (4) lecture octet image
  STB   1,X       (5) affiche l'octet image
  LEAX  2,X       (5) deplacement de 2 octets
  BRA   PLAY3     (3) compensation "BMI PLAY4"
 
* sortie video = 26 cycles
PLAY3
  ORA   #$40      (2) set bit 6
  STA   <$CD      (4) acknowledge
  ANDA  #$3F      (2) clear bit 6
  STA   <$CD      (4) request to send
  LDB   <$CC      (4) lecture octet image
  ORA   #$40      (2) set bit 6
  STA   <$CD      (4) acknowledge
  STB   ,X        (4) affiche l'octet image
 
* echantillon son (14 cycles)
PLAY1
  ANDA  #$3F      (2) clear bit 6
  STA   <$CD      (4) request to send
  LDA   <$CC      (4) lecture echantillon son avec B6
  STA   <$CD      (4) joue le son et acknowledge
 
  BMI   PLAY4     (3) mode 2 octets?
  BNE   PLAY2     (3) fin ?
 
*------------------------------------------------------
* RETOUR AU BASIC
*------------------------------------------------------
  ORA   #$40      (2) set bit 6
  STA   <$CD      (4) acknowledge
 
* retour au Basic
  PULS CC,A,B,DP,X,Y,U,PC 
  
* retour a l'assembleur
*  SWI
  
  END INI
Pourquoi est-ce que 66cycles c'est mieux ? Ca nous fait 15151.5Hz (15 qui se répète), c'est pas non plus un entier. Certes, mais la valeur double 30303.0 est quasi entière, et peut-être passée à FFMPEG sans soucis. Pour l'encodage il suffit de lire les échantillons audio 2 par deux et de prendre leur moyenne pour restituer les 15151.5 d'origine. Cela a en outre l'avantage de réduire le bruit à l'oreille

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.
#
##############################################################################

$file = $ARGV[0];

# params par defaut
mkdir("tmp");
$img_pattern = "tmp/img%05d.bmp";
($w, $h) = (320, 180); # 16:9
$hz  = 15151.5;
$fps = 10;
$interlace = 0;

$BUFFERSIZE = int((3*$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 = int((3*$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(10*$time/$d)/10, $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/3));

# 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;
		eval 'use Image::Magick;';
		# determination de l'espace RGB lineaire
		my $img = Image::Magick->new(size=>"256x1", depth=>16);
		$img->Read('gradient:gray(0)-gray(100%)');
		$img->Set(colorspace=>'RGB');
		my @px1 = $img->GetPixel(x=>184, y=>0);
		$img->Set(colorspace=>'sRGB');
		my @px2 = $img->GetPixel(x=>184, 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(0) {
		#$tmp->Set(monochrome=>"True");
		$tmp->Set(colorspace=>"gray");
		$tmp->Remap(image=>$bw_img, dither=>"True", "dither-method"=>"FloydSteinberg");
	} else {
		# mieux ?
		$tmp->Set(colorspace=>"gray");
		$tmp->OrderedDither(threshold=>"o8x8,2");
		#$tmp->OrderedDither(threshold=>"h8x8a,2");
		#$tmp->OrderedDither(threshold=>"vac-128,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);
	
	# remplissage variable globale @cible
	my(@p) = $img->GetPixels(map=>"RGB", height=>200, width=>320, normalize=>"True");
	
	my($start) = (200-$h)>>1;
	my($stop)  = (200-$start)*960-3;
	@cible = (0)x(40*$start);
	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]);		
	}
	push(@cible, (0)x(40*$start), 1);
	
	if($interlace) {
		for(my $y=$cpt&1; $y<200; $y+=2) {splice(@cible,40*$y,40,(0)x40);}
	}
	
	return 1;
}

# compresse @cible dans $BUFFERSIZE
sub compresse {
	my(@buf) = (0)x$BUFFERSIZE;
	my($ok) = 1;
	my($k);
	my($img_complete) = 0;
	
	# audio
	for(my $i=0; $i<$BUFFERSIZE; $i+=3) {
		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)); $v=255 if $v>255;
		$buf[$i] = ($v>>2) | 0x40;
	}
	
	# video
	my($i) = 0;
	if($pos>=8000) {
		$buf[$i+1] = $pos = 0;
		$buf[$i+2] = ($ecran[$pos] ^= $cible[$pos]); $cible[$pos]=0;
		$i += 3; 
	}
	while($i < $BUFFERSIZE) {
		my $p = $pos % 8000;
		if($p < 7998 && ($cible[$p+1] || $cible[$p+2])) {
			$buf[$i+0] |= 0x80;
			$buf[$i+1] = ($ecran[$p+1] ^= $cible[$p+1]); $cible[$p+1]=0;
			$buf[$i+2] = ($ecran[$p+2] ^= $cible[$p+2]); $cible[$p+2]=0;
			$pos += 2;
		} else {
			my($k) = 1;
			while($k<255 && !$cible[$p+$k]) {++$k;}
			$pos+=$k;
			$k = $p = 0 if ($p+=$k)==8000;
			$buf[$i+1] = $k;
			$buf[$i+2] = ($ecran[$p] ^= $cible[$p]); $cible[$p]=0;
		}
		$i += 3;
	}
	++$realimg if $pos>=8000;
	
	
	# 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 = 0;
	while(&next_image(\*GIN, \*GOUT,$w,$h)) {
		my $p = 0;
		while($p<8000) {
			my $k;
			if($p < 7998 && ($cible[$p+1] || $cible[$p+2])) {
				$k=2;
			} else {
				$k = 1;
				while($k<255 && !$cible[$p+$k]) {++$k;}
			}
			$p+=$k; $size += 3;
		}
		$size += 3; # retour debut
		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);
	}
	unlink(<tmp/img*.bmp>);
	print STDERR "\n";
	my $len_per_img = ($size/($cpt-1)) * (1.15); # 15% extra
	close(GIN);
	close(GOUT);
	my $zoom = $BUFFERSIZE/$len_per_img;
	return $zoom>=1?$zoom:sqrt($zoom);
}
Cela produit les vidéos dispo ici: http://dl.free.fr/bXrBNZ7Qi à lire à partir du programme BASIC suivant:

Code : Tout sélectionner

10 CLEAR,&H8FFF
20 COLOR7,0:SCREEN,,0:CLS:LOCATE1,1,0
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,49,A6,C4,8A,01,A7,C4
100 DATA 1F,30,1F,8B,4F,5F,DD,CE,C6,7F
110 DATA DD,CC,8A,04,97,CE,97,CF,20,2E
120 DATA 84,3F,97,CD,D6,CC,27,04,3A,7E
130 DATA 90,5A,8E,40,00,7E,90,5A,84,3F
140 DATA 97,CD,D6,CC,E7,01,30,02,20,00
150 DATA 8A,40,97,CD,84,3F,97,CD,D6,CC
160 DATA 8A,40,97,CD,E7,84,84,3F,97,CD
170 DATA 96,CC,97,CD,2B,DA,26,C6,8A,40
180 DATA 97,CD,35,FF
190 DATA 9000,**
Beaucoup de video sont full-screen ou quasi-fullscreen (zoom>75%). Les seules qui ont un zoom<=75% sont:

Code : Tout sélectionner

Eric Prydz - Call on me.mp4 : 640x360 (16:9) -> 320x180
avg 320x180 frame length = 7206 bytes (158%) @ 179s
zoom = 0.74 -> 237x133 @ 10fps
0:03:01 (0.3x) v=1:0.931 a=(x+0)*1

Kylie Minogue - Can't Get You Out Of My Head.mp4 : 554x360 (4:3) -> 307x200
avg 307x200 frame length = 7395 bytes (162%) @ 229s
zoom = 0.73 -> 224x146 @ 10fps
0:03:47 (0.3x) v=1:0.945 a=(x-88)*3
Mais on voit qu'elles ne sont vraiment pas loin. Pour elles, le mode "entrelacé" activé en mettant $interlace=1 au début du script serait un gros plus.

Beaucoup de vidéos ont un zoom>1, ce qui veut dire qu'on peut dépasser les 10fps demandés.

Code : Tout sélectionner

Custom Knight rider intro 1 - Classic.flv : 320x240 (4:3) -> 266x200
avg 266x200 frame length = 3184 bytes (70%) @ 73s
zoom = 1.2 -> 266x200 @ 12fps
0:01:13 (0.3x) v=1:0.977 a=(x-46)*2

HollySiz - Come Back To Me [Clip Officiel].flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 2058 bytes (45%) @ 180s
zoom = 1.9 -> 320x180 @ 19fps
0:02:58 (0.2x) v=1:0.93 a=(x+0)*1

Hot Water - Simon's Cat.flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 1620 bytes (35%) @ 147s
zoom = 2.5 -> 320x180 @ 24fps
0:02:25 (0.1x) v=1:0.97 a=(x-65)*2

Jan Hammer - Original Miami Vice Theme ( Miami Vice Tribute video by StevenMighty ).flv : 320x240 (4:3) -> 266x200
avg 266x200 frame length = 3117 bytes (68%) @ 170s
zoom = 1.3 -> 266x200 @ 12fps
0:02:48 (0.2x) v=1:0.964 a=(x-24)*1

Paris Combo - Living Room.flv : 294x240 (4:3) -> 245x200
avg 245x200 frame length = 3193 bytes (70%) @ 252s
zoom = 1.2 -> 245x200 @ 12fps
0:04:13 (0.2x) v=1:0.968 a=(x-18)*1

Space Shuttle Launch Audio - play LOUD (no music) HD 1080p.flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 2626 bytes (57%) @ 234s
zoom = 1.5 -> 320x180 @ 15fps
0:03:52 (0.2x) v=1:0.973 a=(x+0)*1

The Box - Simon's Cat.flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 609 bytes (13%) @ 128s
zoom = 6.5 -> 320x180 @ 65fps
0:00:15 (0x) v=1:0.949 a=(x-78)*2

Washed Up - Simon's Cat.flv : 426x240 (16:9) -> 320x180
avg 320x180 frame length = 786 bytes (17%) @ 148s
zoom = 5.1 -> 320x180 @ 50fps
0:00:32 (0x) v=1:0.984 a=(x-94)*4
0:02:26 (0x) v=1:0.986 a=(x-58)*2

Daft Hands - Harder, Better, Faster, Stronger.mp4 : 540x360 (4:3) -> 300x200
avg 300x200 frame length = 1942 bytes (42%) @ 226s
zoom = 2 -> 300x200 @ 20fps
0:03:44 (0.1x) v=1:0.996 a=(x+0)*1

Indiana Jones Boulder Scene.mp4 : 640x278 (16:9) -> 320x139
avg 320x139 frame length = 1729 bytes (38%) @ 29s
zoom = 2.4 -> 320x139 @ 23fps
0:00:27 (0.1x) v=1:0.944 a=(x-25)*1

Masoud feat. Aneym - No More (Music video))).mp4 : 640x360 (16:9) -> 320x180
avg 320x180 frame length = 2172 bytes (47%) @ 248s
zoom = 1.8 -> 320x180 @ 18fps
0:04:06 (0.2x) v=1:0.991 a=(x+0)*1

Paris Combo - Señor (Live).mp4 : 640x360 (16:9) -> 320x180
avg 320x180 frame length = 2377 bytes (52%) @ 399s
zoom = 1.7 -> 320x180 @ 16fps
0:06:37 (0.2x) v=1:0.994 a=(x+0)*1

Star Trek Genesis.mp4 : 480x360 (4:3) -> 266x200
avg 266x200 frame length = 2255 bytes (49%) @ 67s
zoom = 1.8 -> 266x200 @ 17fps
0:01:05 (0.2x) v=1:0.99 a=(x-123)*8

Star Wars Episode V - The Empire Strikes Back Trailer.mp4 : 540x360 (4:3) -> 300x200
avg 300x200 frame length = 2716 bytes (59%) @ 197s
zoom = 1.5 -> 300x200 @ 14fps
0:03:15 (0.2x) v=1:0.965 a=(x+0)*1

Star Wars- Return Of The Jedi Trailer (HD).mp4 : 640x360 (16:9) -> 320x180
avg 320x180 frame length = 2706 bytes (59%) @ 131s
zoom = 1.5 -> 320x180 @ 14fps
0:02:11 (0.2x) v=1:0.954 a=(x-11)*1

Star Wars The Force Awakens Special Extended Trailer.mp4 : 1280x720 (16:9) -> 320x180
avg 320x180 frame length = 2590 bytes (56%) @ 149s
zoom = 1.5 -> 320x180 @ 15fps
0:02:28 (0.2x) v=1:0.949 a=(x+0)*1

THE ABYSS - Trailer ( 1989 ).mp4 : 540x360 (4:3) -> 300x200
avg 300x200 frame length = 1730 bytes (38%) @ 177s
zoom = 2.3 -> 300x200 @ 22fps
0:02:56 (0.1x) v=1:0.974 a=(x+0)*1
On peut y remarquer que, comme attendu, les simon's cat sont largement à plus de 10fps, et atteignent même 65fps, ce qui est largement de trop (la bande passante est trop grosse pour eux)

Bonne visu sur émulateur. On attendra le retour de Daniel pour voir si le protocole par simple front serait possible (les 18kHz me font super de l'œil).

A noter: un truc que je ne m'explique pas.

Le tramage de Bayer 8x8 s'encode mieux que le void-and-cluster 8x8. C'est pas logique car les deux sont basés sur les mêmes tuiles 8x8 et les deux ont la propriété qu'un seul pixel ne s'allume quand on passe d'une intensité à la suivante. Pourquoi le mode 2octets a l'air de mieux tirer parti de la régularité inter-tuile du tramage de Bayer? Certes, il regarde les octets changés, mais pas leur contenu, et donc n'exploite pas de régularité entre octets identiques. Non vraiment je ne comprends pas pourquoi Bayer s'encode mieux. Peut-être est-ce lié au fait qu'entre les niveaux n et n+4, c'est le même octet qui est changé, favorisant les changements sur le même octet... mais encore ca n'est pas vrai entre n et n+3 ou n et n+5. Donc pas grand chose de significatif je pense.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 30 juin 2015 13:53

Et la couleur alors ? Comment se comporte l'encodage couleur avec le mode "2 octets" ?

Et bien il se comporte très bien lui aussi. A peine 6 ou 8 sur les 43 ne passent pas à plus de 75% du full-screen, et parfois de peu.

Vous voulez savoir lequelles ? Téchargez le zip suivant: http://dl.free.fr/kzwbKDXj7, et lancez l'émulateur de Daniel (inclus dans l'archive). Choisissez un basic, puis avec l'émulation clavier depuis le presse-papier, tapez le programme suivant:

Code : Tout sélectionner

10 CLEAR,&H8FFF
20 COLOR7,0:SCREEN,,0:CLS:LOCATE1,1,0
25 CONSOLE,,0:FOR I=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,49,A6,C4,8A,01,A7,C4
100 DATA 1F,30,1F,8B,4F,5F,DD,CE,C6,7F
110 DATA DD,CC,8A,04,97,CE,97,CF,20,2E
120 DATA 84,3F,97,CD,D6,CC,27,04,3A,7E
130 DATA 90,5A,8E,40,00,7E,90,5A,84,3F
140 DATA 97,CD,D6,CC,E7,01,30,02,20,00
150 DATA 8A,40,97,CD,84,3F,97,CD,D6,CC
160 DATA 8A,40,97,CD,E7,84,84,3F,97,CD
170 DATA 96,CC,97,CD,2B,DA,26,C6,8A,40
180 DATA 97,CD,35,FF
190 DATA 9000,**
Dans le menu "Supports amovibles" choisissez l'un des SD dans "Fichier sur carte SD", et tapez RUN..

Dans l'ensemble le résultat est bluffant quand on se dit que ca tourne sur des vulgaires TO7/MO5 du plan IPT aux graphismes généralement très pauvres et peu animés. Si j'avais imaginé à l'époque voir "Money For Nothing" sur mon TO7, je ne l'aurais pas cru.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Daniel
Messages : 11694
Enregistré le : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

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

Message par Daniel » 30 juin 2015 15:20

Un peu de vacances de temps en temps ne fait pas de mal. Même sans ordinateur j'ai pas mal réfléchi à la façon d'augmenter le débit de transmission. L'idée de __sam__ (synchronisation sur front montant ou descendant) est très bonne mais j'ai été encore beaucoup plus loin pour atteindre 120 000 octets par seconde en streaming audio.

Le schéma de l'interface n'a pas changé. Le programme Thomson est d'une simplicité exemplaire :

Code : Tout sélectionner

*------------------------------------------------------
* LECTURE SEQUENTIELLE
* 75 cycles pour 9 echantillons = 120 kHz
*------------------------------------------------------
LECT0
  LDA   <$CC      (4) lecture octet 1
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 2
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 3
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 4
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 5
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 6
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 7
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 8
  STA   <$CD      (4) sortie son
  LDA   <$CC      (4) lecture octet 9
  STA   <$CD      (4) sortie son
  BPL   LECT0     (3) nouvelle lecture
L'astuce est de préparer le fichier son 6 bits à 120 000 échantillons par seconde, en alternant le bit 6 à 0 et 1 pour la synchronisation. Le bit 7 est utilisé pour la détection de fin de fichier.

Le plus difficile a été de mettre au point le sketch Arduino pour suivre cette cadence infernale. Surtout que je n'ai pratiquement pas de moyen pour analyser les entrées/sorties et vérifier le timing. Pour aller à cette vitesse, la synchronisation n'est assurée qu'un octet sur deux. L'autre octet est envoyé exactement entre ces voisins grâce à des temporisations. Mais croyez-moi, ça n'a pas été facile. En particulier j'ai réécrit la lecture de la carte SD pour éviter les appels à des fonctions de la bibliothèque. Finalement ça fonctionne bien à 120 000 octets/s. Le maximum théorique est 125 000 octets/s, mais pour gagner 4% ça ne vaut pas le coup d'y consacrer trop de temps. J'ai choisi 120 000 octets/s car c'est un compte rond, mais il faut 9 lectures par boucle. Un nombre pair serait peut-être mieux : par exemple 16 octets en 131 cycles, soit 122137,4 octets/s.

Pour transposer à la vidéo je pense qu'il faut mettre 4 ou 5 octets d'image, suivis d'un octet de son servant à la synchronisation. En ajustant les temporisations, on doit pouvoir faire arriver les octets d'image au bon moment. Evidemment le traitement sur Thomson consommera quelques cycles supplémentaires et fera baisser le débit, mais on devrait pouvoir doubler la vitesse des démos précédentes. Il y a encore du travail, mais je voulais partager ce résultat, obtenu il y a moins d'une heure.

Maintenant je vais pouvoir me reposer en visionnant les nouvelles vidéos de __sam__ sur le (vrai) MO5 :wink:
Daniel
L'obstacle augmente mon ardeur.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 30 juin 2015 19:14

120ko/sec très cool, mais du coup je ne comprends pas bien comment on insère le bit 6 dans les octets videos. Il n'y en a plus c'est ca ? C'est juste le timing coté arduino qui compte. Ca va être chaud: la moindre irrégularité dans le flot et tout se décale. Ca ne va pas non plus être simple à mettre dans l'émulateur je suppose (a moins de compter les accès en lecteur aux PIA).

Sinon pour voir mes videos, je te recommande de voir celle depuis l'avancée de vendredi. Franchement le mode "2octets" boost vraiment bien (N&B en 1er puis couleur en 2nd). On a un débit 2x en octets video pour les zones avec des octets consécutifs modifiés.

Pour encore améliorer la vitesse en soft pur j'ai testé le coup de l'entrelacement. Ca double à nouveau la bande passante (moralement). Pour le noir & blanc ca marche bien, et pour la couleur j'entrelace une ligne verte avec les deux lignes rouge+bleu ensemble (La somme rouge+bleu donne une intensité très voisine de la verte seule, ce qui équilibre).

Les tests on montrés que la bande passante est effectivement améliorée (plein écran, et 30fps pour les démos amiga). Question qualité du rendu, ca marche pas mal sur les vidéos "calmes", mais quand ca bouge beaucoup (plans de coupe) et qu'on manque de bande passante (l'image ne se termine pas dans le temps imparti), on voit apparaitre les lignes vertes trop longtemps et ca fait étrange (rémanence).

Du coup, je réfléchis à l'idée d'un entrelacement adaptatif: Si on a de la bande passante "moyenne", on peut entrelacer V et R+B; et si c'est tendu (trop de changements), on bascule sur du non-entrelacé le temps que ca se calme car l'effet visuel sera moins pire que ces fantomes verts (ou magenta suivant la frame qui reste trop longtemps visible). Ca devrait aider pour les clips très dynamiques, mais pour les clips normaux ("calmes"), l'entrelacement seul marche très bien aussi.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Daniel
Messages : 11694
Enregistré le : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

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

Message par Daniel » 30 juin 2015 20:39

__sam__ a écrit :je ne comprends pas bien comment on insère le bit 6 dans les octets videos. Il n'y en a plus c'est ca ? C'est juste le timing coté arduino qui compte. Ca va être chaud: la moindre irrégularité dans le flot et tout se décale.
C'est ce que j'ai imaginé. Il faut que le programme Thomson déroule un nombre fixe de cycles pour chacun des octets vidéo. Ce nombre de cycles peut être différent entre le premier, le deuxième, le troisième octet, etc. Ensuite l'octet audio rétablit la synchronisation. Sur quatre ou cinq octets il ne doit pas y avoir de grosse dérive, mais ça reste à vérifier, en particulier aux frontières de blocs.
__sam__ a écrit :Ca ne va pas non plus être simple à mettre dans l'émulateur je suppose (a moins de compter les accès en lecteur aux PIA).
Dans dcmoto les octets de la carte SD sont envoyés séquentiellement à chaque lecture en $A7CC/$E7CC. Les bits de synchronisation sont inutilisés. Ce n'est pas fidèle au matériel mais l'avantage est la simplicité. L'inconvénient : si ça marche dans l'émulateur, ça ne marche pas forcément avec l'Arduino. Par contre, si ça marche avec l'Arduino, ça marche aussi dans dcmoto.

Au cours de mes essais, j'ai fait un test de vitesse de lecture de la carte SD par l'Arduino avec mes propres routines. C'est de l'ordre de 250 Ko/s, donc largement supérieur à la vitesse de lecture du 6809. On a de la marge. Je souris quand je vois écrit un peu partout que l'Arduino ne peut guère dépasser 20 kHz pour la lecture des fichiers .wav. Je peux faire dix fois plus vite ! L'expérience de la carte SD acquise avec SDMOTO m'a été très utile. Je n'ai trouvé personne dans la communauté Arduino ayant pratiqué ce genre de sport avec la commande CMD18 et la lecture physique octet par octet.
Daniel
L'obstacle augmente mon ardeur.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 30 juin 2015 22:28

Daniel a écrit :Dans dcmoto les octets de la carte SD sont envoyés séquentiellement à chaque lecture en $A7CC/$E7CC. Les bits de synchronisation sont inutilisés. Ce n'est pas fidèle au matériel mais l'avantage est la simplicité. L'inconvénient : si ça marche dans l'émulateur, ça ne marche pas forcément avec l'Arduino. Par contre, si ça marche avec l'Arduino, ça marche aussi dans dcmoto.
Ah ok. Ca signifie que c'est pas parce que le mode "2 octets" marche sur emul qu'il marchera sur arduino. En revanche cela permettrait de tester le mode "front montant/descendant" simplement.
Au cours de mes essais, j'ai fait un test de vitesse de lecture de la carte SD par l'Arduino avec mes propres routines. C'est de l'ordre de 250 Ko/s, donc largement supérieur à la vitesse de lecture du 6809.
Comment ca se passe au niveau des inter-blocs coté arduino? S'il faut 5ms pour passer au bloc suivant, le 6809 lit un truc que n'a pas écrit l'arduino qui est resté bloqué sur l'attente du bloc suivant. Qu'est ce qui nous sauve dans ce cas là? le timing? (exemple: c'est 5µs l'interbloc et pas 5ms).
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Daniel
Messages : 11694
Enregistré le : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

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

Message par Daniel » 01 juil. 2015 08:30

Les modes "2 octets" monochrome et couleur marchent parfaitement avec l'Arduino et le MO5, je les ai testé hier. Une petite remarque au passage : en Basic 1.0 la syntaxe LOCATE,,0 est invalide, il faut écrire LOCATE0,0,0.

Le streaming audio à 120000 octets/seconde marche sur Arduino et sur dcmoto_nouveau version 20150630. Le son n'est pas parfait, car dcmoto le restitue à 22050 échantillons/seconde avec, évidemment, quelques arrondis. Mais c'est quand même très bon.

Pour la vidéo à 120000 octets/seconde (valeur théorique, en pratique le traitement de décompression diminuera le débit), la mise au point du programme Thomson peut se faire avec dcmoto 20150630. Restera ensuite à adapter le sketch Arduino en tenant compte du nombre de cycles entre chaque lecture. Le fichier .sd doit contenir des séquences de n octets vidéo, séparées par un octet audio. Cet octet audio a le bit 6 alternativement à 1 et 0, et le bit 7 à zéro, sauf le dernier échantillon avec le bit 7 à 1 pour indiquer la fin de fichier.

Je ne me suis pas encore préoccupé du délai interblocs. C'est quelques microsecondes, et pour l'audio ça ne s'entend pas. Au pire le même échantillon est répété deux ou trois fois, mais à 120 kHz l'oreille humaine ne peut pas le percevoir. Pour la vidéo, il serait judicieux de mettre un échantillon audio au début de chaque bloc de 512 octets, ce qui permettrait de rattraper l'écart et de synchroniser les octets suivants. Si la longueur de la séquence de permet pas de s'aligner sur des frontières de blocs, on peut ajouter deux ou trois octets de remplissage en fin de bloc pour rétablir l'alignement, je pense que le décalage sera imperceptible.
Daniel
L'obstacle augmente mon ardeur.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 01 juil. 2015 11:16

Oui pour le locate j'avais vu, et c'etait modifié dans la version couleur ci-dessus.

Toujours sur la couleur, je me suis rendu compte que les vidéos les moins belles sont les plus sombres. C'est logique: sur les basses intensité, le tramage deviens moins précis (9pix en x et 9 pix en y pour la plus basse intensité couleur). J'ai expérimenté et vu que ces vidéos moches avaient des valeurs max très faibles style 110/255, par contre les belles utilisaient bien toute l'échelle des 255 valeurs possible (ca se voit sur l'histogramme des intensités).

Aussi j'ai mis au point l'algo suivant: je fais un histogramme de tous les pixels cumulés sur toutes les images. Puis je calcul un facteur multiplicatif qui envoie 4% des pixels les plus lumineux au delà de la valeur max de l'histogramme. Cela revient à volontairement cramer/sur-exposer 4% des intensités les plus lumineuses du film. C'est à peine visible, mais a l'arrivée le film est totalement re-normalisé et utilise bien toute l'étendue possible des intensités. Les couleurs sont plus vives, l'image est plus belle. C'est bien mieux.

Le resultat est assez stupéfiant. Certaines videos "ternes" sont super belle avec de très beaux contrastes sur thomson. Je passerait une version préliminaire de l'algo dans peu de temps. Idem pour les résultats....
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 01 juil. 2015 23:00

__sam__ a écrit :Je passerait une version préliminaire de l'algo dans peu de temps. Idem pour les résultats....
Dont acte: voici le script "autoporteur" que j'ai utilisé (plus besoin de thresholds.xml)

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.
#
##############################################################################

$file = $ARGV[0];

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

$BUFFERSIZE = int((3*$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 = int((3*$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/3));

# 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*4/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;
	
	# audio
	for(my $i=0; $i<$BUFFERSIZE; $i+=3) {
		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) | 0x40;
	}
	
	# video
	my($i) = 0;
	if($pos>=8000) {
		$buf[$i+1] = $pos = 0;
		$buf[$i+2] = ($ecran[$pos] ^= $cible[$pos]); $cible[$pos]=0;
		$i += 3; 
	}
	while($i < $BUFFERSIZE) {
		my $p = $pos % 8000;
		if($p < 7998 && ($cible[$p+1] || $cible[$p+2])) {
			$buf[$i+0] |= 0x80;
			$buf[$i+1] = ($ecran[$p+1] ^= $cible[$p+1]); $cible[$p+1]=0;
			$buf[$i+2] = ($ecran[$p+2] ^= $cible[$p+2]); $cible[$p+2]=0;
			$pos += 2;
		} else {
			my($k) = 1;
			while($k<255 && !$cible[$p+$k]) {++$k;}
			$pos+=$k;
			$k = $p = 0 if ($p+=$k)==8000;
			$buf[$i+1] = $k;
			$buf[$i+2] = ($ecran[$p] ^= $cible[$p]); $cible[$p]=0;
		}
		$i += 3;
	}
	++$realimg if $pos>=8000;
	
	
	# 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 = 0;
	$phase = 1;
	while(&next_image(\*GIN, \*GOUT,$w,$h)) {
		my $p = 0;
		while($p<8000) {
			my $k;
			if($p < 7998 && ($cible[$p+1] || $cible[$p+2])) {
				$k=2;
			} else {
				$k = 1;
				while($k<255 && !$cible[$p+$k]) {++$k;}
			}
			$p+=$k; $size += 3;
		}
		$size += 3; # retour debut
		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.15); # 15% extra
	close(GIN);
	close(GOUT);
	my $zoom = $BUFFERSIZE/$len_per_img;
	return $zoom>=1?$zoom:sqrt($zoom);
}
Le résultat est là: http://dl.free.fr/kUuO4hm2P (il y a un peu de tout, mais Dire-Straits, K2000, Sugar Rush, The Abyss sont nettement mieux)
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 01 juil. 2015 23:34

Daniel a écrit :Pour la vidéo à 120000 octets/seconde (valeur théorique, en pratique le traitement de décompression diminuera le débit), la mise au point du programme Thomson peut se faire avec dcmoto 20150630. Restera ensuite à adapter le sketch Arduino en tenant compte du nombre de cycles entre chaque lecture. Le fichier .sd doit contenir des séquences de n octets vidéo, séparées par un octet audio. Cet octet audio a le bit 6 alternativement à 1 et 0, et le bit 7 à zéro, sauf le dernier échantillon avec le bit 7 à 1 pour indiquer la fin de fichier.
Pour fixer les idées je suis parti du player "2octets" auquel j'ai retiré le protocole de syncho pour ne garder que la synchro sur réception de l'octet audio.

Code : Tout sélectionner

  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   NEWPIC+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
 
  BRA   PLAY1
 
*------------------------------------------------------
* JOUE LA VIDEO ET LA MUSIQUE
* Boucle de 36 cycles = 27777.78 Hz
*------------------------------------------------------
 
* lecture octet depl = 14 cycles
PLAY2
  LDB   <$CC      (4) lecture octet deplacement
  BEQ   NEWPIC    (3) nouvelle image
  ABX             (3) ajout de l'increment
  JMP   PLAY3     (4) octet video
 
* retour debut ecran = 7 cycle
NEWPIC
  LDX  #$4000     (3)
  JMP  PLAY3      (4)
  
* mode 2 octets: 14+3 cycles
PLAY4
  LDB   <$CC      (4) lecture octet image
  STB   1,X       (5) affiche l'octet image
  LEAX  2,X       (5) deplacement de 2 octets
  BRA   PLAY3     (3) compensation "BMI PLAY4"
 
* sortie video = 8 cycles
PLAY3
  LDB   <$CC      (4) lecture octet image
  STB   ,X        (4) affiche l'octet image
 
* echantillon son (8 cycles)
PLAY1
  LDA   <$CC      (4) lecture echantillon son avec B6 alternant
  STA   <$CD      (4) joue le son et acknowledge
 
  BMI   PLAY4     (3) mode 2 octets?
  BNE   PLAY2     (3) fin ?
 
*------------------------------------------------------
* RETOUR AU BASIC
*------------------------------------------------------
 
* retour au Basic
  PULS CC,A,B,DP,X,Y,U,PC 
  
* retour a l'assembleur
*  SWI
  
  END INI
En basic:

Code : Tout sélectionner

10 CLEAR,&H8FFF
20 COLOR7,0:SCREEN,,0:CLS:LOCATE0,0,0
25 'CONSOLE,,0:FOR I=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,A6,C4,8A,01,A7,C4
100 DATA 1F,30,1F,8B,4F,5F,DD,CE,C6,7F
110 DATA DD,CC,8A,04,97,CE,97,CF,20,1A
120 DATA D6,CC,27,04,3A,7E,90,52,8E,40
130 DATA 00,7E,90,52,D6,CC,E7,01,30,02
140 DATA 20,00,D6,CC,E7,84,96,CC,97,CD
150 DATA 2B,EE,26,DE,35,FF
160 DATA 9000,**
Ce player tourne à 36cycles, soit 27.78kHz, soit sensiblement 2x la fréquence du player précédent, ce qui promet un son excellent (hormis fréquence coupure) et des FPS élevés.

Je l'ai expérimenté avec dcmoto_nouveau du 30 juin sur ce fichier: http://www.cjoint.com/doc/15_07/EGbvES6 ... r-Scene.7z (audio à 36fps), dont les octets audio (1 sur 3) alternent le bit 6

Code : Tout sélectionner

0000000 00 00 00 40 ff 00 00 ff 00 40 ff 00 00 ff 00 40
0000020 ff 00 00 e1 20 c0 20 20 00 9e 08 40 2b 80 00 51
0000040 10 40 25 20 80 20 00 c0 20 00 00 27 0a 40 29 40
0000060 00 4d 08 c0 00 08 80 08 00 40 1b 80 00 0b 80 c0
0000100 80 00 00 26 04 40 4c 20 80 20 20 c0 20 20 80 20
0000120 20 40 26 0a 00 28 40 40 4e 08 80 08 08 c0 08 00
0000140 80 08 00 40 22 80 80 80 80 c0 80 00 80 00 80 40
0000160 24 04 00 2b 01 40 19 20 00 03 20 c0 20 20 80 20
0000200 20 c0 20 20 80 20 20 c0 20 20 80 20 20 c0 20 00
Mais à l'écran je n'ai que du blanc :(

J'ai utilisé le debuggeur intégré et constaté que je ne lisais en <$CC que $FF, c'est à dire que je ne retrouve pas le contenu du SD. Qu'est ce que je fais de travers ?
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Daniel
Messages : 11694
Enregistré le : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

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

Message par Daniel » 02 juil. 2015 14:55

Après les initialisations, il y a un BRA PLAY1.
Le LDA charge le premier octet du fichier, qui est égal à $00.
Le BMI continue en séquence, le BNE aussi, on revient alors au Basic.

Code : Tout sélectionner

    PLAY1
      LDA   <$CC      (4) lecture echantillon son avec B6 alternant
      STA   <$CD      (4) joue le son et acknowledge

      BMI   PLAY4     (3) mode 2 octets?
      BNE   PLAY2     (3) fin ?

*------------------------------------------------------
* RETOUR AU BASIC
*------------------------------------------------------

* retour au Basic
  PULS CC,A,B,DP,X,Y,U,PC
  
Les vidéos 2octets couleur sont nettement mieux avec le nouvel algorithme, en particulier sur le vrai MO5. Je me demande si on ne pourrait pas encore aller plus loin, pour éclaircir encore l'image, quitte à saturer un peu les blancs (mais sans éclaircir les noirs). En augmentant le contraste on perd des nuances, mais compte tenu de la mauvaise résolution ce n'est pas très gênant. Et une image plus contrastée me semble plus agréable à l'oeil.
Daniel
L'obstacle augmente mon ardeur.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 02 juil. 2015 17:15

Tiens c'est curieux, dans le debuggeur je n'ai pas vud de $00 chargé, uniquement des $FF. J'ai du louper un truc.

Pour saturer encore plus les blancs il suffit de remplacer 4/100 (4%) par une valeur plus haute: 5/100 ou 10/100 dans le code

Code : Tout sélectionner

   if($phase==2) {
      my $tot = -$stat[0];
      for my $p (@stat) {$tot += $p;}

      my $thr = $tot*4/100; # <====== ICI
      $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;
   } 
Je pense que 10/100 sera beaucoup par contre.
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 02 juil. 2015 22:29

Ah oui je viens de comprendre que le codage "2octets" ne marchera pas car le bit b6 est utilisé pour la fin de fichier et que donc son alternance va faire sortir tout de suite de la boucle. Neamoins, ca n'est pas le vrai pb. J'ai fait le code ASM suivant:

Code : Tout sélectionner

  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
  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
  
loop
  ldb <$CC
  bra loop
(init + bouclage en lecture du port A) et avec le debuggeur le regarde ce qu'il passe sur le port A (<$CC).

Avec un fichier débutant par

Code : Tout sélectionner

0000000 c0 00(00)ff 00(ff)00 80(ff)00 ff(00)ff 00(c0)3e
0000020 08(a0)20 01(20)80 02 20(01)20 01 20 c0(26)02 78
0000040 (08)02 08(80)29 80(01)80 50(10)c0 25(20)01 20(02)
j'observe: 00 FF FF 00 C0 A0 20 01 26 08 80 01 10 20 02 ce qui ressemble beaucoup (aux erreurs de recopies près) à 1 octet sur 3 (j'ai mis des parenthèses autour). Je ne vois pas trop ce qui peut faire compter de 3 en 3 dans la boucle "loop". Il y a un truc ??
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Daniel
Messages : 11694
Enregistré le : 01 mai 2007 18:30
Localisation : Vaucluse
Contact :

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

Message par Daniel » 03 juil. 2015 18:23

J'ai fait un petit test qui confirme le problème. C'est le debugger qui provoque une incrémentation non voulue de l'index de la carte SD. Pour afficher la valeur de $A7CC dans la liste "Registres des périphériques", il lit $A7CC à chaque instruction. Chaque lecture fait +1 dans l'index. Comme il y a 2 instructions dans la boucle, il y a 2 incrémentations inopportunes, plus une normale, ce qui fait augmenter l'index de 3. Si le debugger n'est pas ouvert, il n'y a pas d'erreur.

Je vais corriger dès que possible, mais on peut quand même tester avec la version actuelle sans utiliser le debugger.
Daniel
L'obstacle augmente mon ardeur.

__sam__
Messages : 4617
Enregistré le : 18 sept. 2010 12:08
Localisation : Brest et parfois les Flandres

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

Message par __sam__ » 03 juil. 2015 18:36

Arf.... les effets de bord rigolos et difficiles à prévoir quand on imagine pas le cas d'usage. J'adore ceux-là :)

Pour des facilité de codage j'ai fait en sorte que le bit de signe de l'octet son soit à 1 tant qu'on a pas fini le fichier (en fin de fichier on ne lit plus que des 0 apparemment). J'arrive à caser 3 doublets vidéos à 21 cycles suivis par un octet son (8 cycles) pour un total de 74 cycles, soit une période audio de 13513.5Hz (le double est quasi entier) durant laquelle 3 échantillons vidéos sont affichés (au lieu de 1 ou 2 avec l'algo "2octets"). Le code est le suivant:

Code : Tout sélectionner

/*--------------------------------------------------------------*
 * Compilé avec C6809 v0.83                                     *
 *--------------------------------------------------------------*
 * Fichier source      : sdplay3.ass
 * Fichier destination : SDPLAY3.BIN
 * Contenu :
 *     Main     0:sdplay2.ASM  1909
 *--------------------------------------------------------------*/

Macro Pass
Pass1
Pass2
      2        9000                 ORG   $9000
      3        9000               INI
      4  5+10  9000 34   7F         PSHS  U,Y,X,DP,B,A,CC  empile les regis>>
      5  2     9002 1A   50         ORCC  #$50      masque les interruption>>
      6  3     9004 8E   1F40       LDX   #$1F40    adresse pour test RAM o>>
      7  4+0   9007 E6   84         LDB   ,X        lecture adresse X
      8  6+0   9009 63   84         COM   ,X        tente de modifier adres>>
      9  4+0   900B E1   84         CMPB  ,X        test modification adres>>
     10  3     900D 27   0A         BEQ   INIT1     pas de difference -> TO>>
     11  6+0   900F 63   84         COM   ,X        retablissement adresse >>
     12  3     9011 CE   A7C0       LDU   #$A7C0    port A du PIA systeme
     13  3     9014 8E   0000       LDX   #$0000    adresse dans ecran
     14  3     9017 20   06         BRA   INIT2     suite des initialisatio>>
     15        9019               INIT1
     16  3     9019 CE   E7C3       LDU   #$E7C3    port A du PIA systeme
     17  3     901C 8E   4000       LDX   #$4000    adresse dans ecran
     18        901F               INIT2
     19  6     901F BF   9048       STX   NEWPICa+1 adresse debut ecran
     20  6     9022 BF   9058       STX   NEWPICb+1 adresse debut ecran
     21  6     9025 BF   9068       STX   NEWPICc+1 adresse debut ecran
     22  4+0   9028 A6   C4         LDA   ,U        port A du PIA systeme
     23  2     902A 8A   01         ORA   #1        set bit 0
     24  4+0   902C A7   C4         STA   ,U        passage en video forme
     25  6     902E 1F   30         TFR   U,D       extraction base $E7/$A7>>
     26  6     9030 1F   8B         TFR   A,DP      initialisation DP
     27  2     9032 4F              CLRA            A=$00
     28  2     9033 5F              CLRB            B=$00
     29  5     9034 DD   CE         STD   <$CE      selectionne DDRA et DDR>>
     30  2     9036 C6   7F         LDB   #$7F      B=$7F
     31  5     9038 DD   CC         STD   <$CC      PA b0-7 en entree, PB b>>
     32  2     903A 8A   04         ORA   #$04      set b2
     33  4     903C 97   CE         STA   <$CE      selectionne PORTA
     34  4     903E 97   CF         STA   <$CF      selectionne PORTB
     35                            
     36                           *---------------------------------------->>
     37                           * JOUE LA VIDEO ET LA MUSIQUE
     38                           * Boucle de 74 cycles = 13513.51 Hz
     39                           *---------------------------------------->>
     40
     41        9040               START
     42
     43                           * 13+8=21 cycles
     44                           PLAY macro
     45                            
     46                           * lecture octet depl = 13 cycles
     47                             LDB   <$CC      (4) lecture octet depla>>
     48                             BEQ   NEWPIC\0  (3) nouvelle image
     49                             ABX             (3) ajout de l'incremen>>
     50                             BRA   PLAY3\0   (3) octet video
     51                            
     52                           * retour debut ecran = 6 cycle
     53                           NEWPIC\0
     54                             LDX  #$4000     (3)
     55                             BRA  PLAY3\0    (3)
     56                            
     57                           * sortie video = 8 cycles
     58                           PLAY3\0
     59                             LDB   <$CC      (4) lecture octet image>>
     60                             STB   ,X        (4) affiche l'octet ima>>
     61                             endm
     62                            
     45                            
     46                           * lecture octet depl = 13 cycles
     47  4     9040 D6   CC         LDB   <$CC      (4) lecture octet depla>>
     48  3     9042 27   03         BEQ   NEWPICa  (3) nouvelle image
     49  3     9044 3A              ABX             (3) ajout de l'incremen>>
     50  3     9045 20   05         BRA   PLAY3a   (3) octet video
     51                            
     52                           * retour debut ecran = 6 cycle
     53        9047               NEWPICa
     54  3     9047 8E   4000       LDX  #$4000     (3)
     55  3     904A 20   00         BRA  PLAY3a    (3)
     56                            
     57                           * sortie video = 8 cycles
     58        904C               PLAY3a
     59  4     904C D6   CC         LDB   <$CC      (4) lecture octet image>>
     60  4+0   904E E7   84         STB   ,X        (4) affiche l'octet ima>>
     45                            
     46                           * lecture octet depl = 13 cycles
     47  4     9050 D6   CC         LDB   <$CC      (4) lecture octet depla>>
     48  3     9052 27   03         BEQ   NEWPICb  (3) nouvelle image
     49  3     9054 3A              ABX             (3) ajout de l'incremen>>
     50  3     9055 20   05         BRA   PLAY3b   (3) octet video
     51                            
     52                           * retour debut ecran = 6 cycle
     53        9057               NEWPICb
     54  3     9057 8E   4000       LDX  #$4000     (3)
     55  3     905A 20   00         BRA  PLAY3b    (3)
     56                            
     57                           * sortie video = 8 cycles
     58        905C               PLAY3b
     59  4     905C D6   CC         LDB   <$CC      (4) lecture octet image>>
     60  4+0   905E E7   84         STB   ,X        (4) affiche l'octet ima>>
     45                            
     46                           * lecture octet depl = 13 cycles
     47  4     9060 D6   CC         LDB   <$CC      (4) lecture octet depla>>
     48  3     9062 27   03         BEQ   NEWPICc  (3) nouvelle image
     49  3     9064 3A              ABX             (3) ajout de l'incremen>>
     50  3     9065 20   05         BRA   PLAY3c   (3) octet video
     51                            
     52                           * retour debut ecran = 6 cycle
     53        9067               NEWPICc
     54  3     9067 8E   4000       LDX  #$4000     (3)
     55  3     906A 20   00         BRA  PLAY3c    (3)
     56                            
     57                           * sortie video = 8 cycles
     58        906C               PLAY3c
     59  4     906C D6   CC         LDB   <$CC      (4) lecture octet image>>
     60  4+0   906E E7   84         STB   ,X        (4) affiche l'octet ima>>
     66                            
     67                           * echantillon son (8 cycles)
     68  4     9070 96   CC         LDA   <$CC      (4) lecture echantillon>>
     69  4     9072 97   CD         STA   <$CD      (4) joue le son et ackn>>
     70
     71                           * sortie ?
     72  3     9074 2B   CA         BMI   START     (3)
     73                            
     74                           *---------------------------------------->>
     75                           * RETOUR AU BASIC
     76                           *---------------------------------------->>
     77                            
     78                           * retour au Basic
     79  5+12  9076 35   FF         PULS CC,A,B,DP,X,Y,U,PC
     80                            
     81                           * retour a l'assembleur
     82                           *  SWI
     83                            
     84                  9000       END INI
soit en basic

Code : Tout sélectionner

10 CLEAR,&H8FFF
20 COLOR7,0:SCREEN,,0:CLS:LOCATE0,0,0
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,**
Avec le fichier SD zippé suivant: http://www.cjoint.com/data/EGdrZkJV8ur_ ... r-Scene.7z

Code : Tout sélectionner

0000000 00 00 ff 00 ff 00 c0 ff 00 ff 00 ff 00 80 3e 08
0000020 a0 20 01 20 c0 02 20 01 20 01 20 80 26 02 78 08
0000040 02 08 c0 29 80 01 80 50 10 80 25 20 01 20 02 20
0000060 c0 28 0a 29 40 27 11 80 26 08 01 08 01 08 c0 01
...
Mais ca marche pas (affichage de blancs à reculons à l'écran). Je ne vois pas ce qui cloche dans le code ASM. Au débuggeur un point d'arret en $9072 montre que le 1er échantillon son ($C0) est correctement lu. C'est après que ca ne marche plus. Je ne vois pas pourquoi (hors débuggeur bien entendu).
Samuel.
A500 Vampire V2+, A1200(030@50mhz/fpu/64mb/cf 8go),
GVP530 (MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.

Répondre