Xuggler: modificare LSB nelle varie immagini di un video

di il
20 risposte

Xuggler: modificare LSB nelle varie immagini di un video

Salve a tutti,
sto sviluppando un software per scopi steganografici su file video: il mio goal e' modificare i vari LSB delle immagini. Per semplificare la gestione ho scelto di utilizzare Xuggler.

Mettendo da parte le logiche di crittografia e di scelta di quale frame e quale pixel conterra' nel suo LSB l'informazione criptata, chiedo supporto per il metodo di modifica runtime del LSB.

Considerando la seguente classe:

public class VideoHandler {
	private String filename;
	private IContainer container;
	private IMediaReader mediaReader;
	
	public VideoHandler(String filename){
    	this.filename=filename;
    	// Xuggler container object creation
        container = IContainer.make();
        // Attempt to open up the container
        int result = container.open(filename, IContainer.Type.READ, null);
        if (result<0){
            throw new RuntimeException("Failed to open media file");
        }
        mediaReader = ToolFactory.makeReader(filename);
    }
	
	//frame = numero del frame dove verra' modificato il LSB
	//x e y coordinate del pixel che verra' modificato
	//bitValue = il valore da inserire nel LSB
	public void setBit(long frame,int x,int y,boolean bitValue){
		
		return;
	}
	
	public int getNumStreams(){
		return container.getNumStreams();
	}
	
	public long getDuration(){
		return container.getDuration();
	}
	
	public long getFileSize(){
		return container.getFileSize();
	}
	
	public long getBitRate(){
		return container.getBitRate();
	}
	public long getStartTime(){
		return container.getStartTime();
	}
	
	public Type getStreamCodecType(int streamNumber){
		IStream stream = container.getStream(streamNumber);
		IStreamCoder coder = stream.getStreamCoder();
		return coder.getCodecType();
	}
	public ID getStreamCodecID(int streamNumber){
		IStream stream = container.getStream(streamNumber);
		IStreamCoder coder = stream.getStreamCoder();
		return coder.getCodecID();
	}
	public long getStreamDuration(int streamNumber){
		IStream stream = container.getStream(streamNumber);
		return stream.getDuration();
	}
	public int getVideoWidth(int streamNumber){
        IStream stream = container.getStream(streamNumber);
        IStreamCoder coder = stream.getStreamCoder();
        if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
        	return coder.getWidth();
        }
        return -1;
        
	}
	public int getVideoHeight(int streamNumber){
        IStream stream = container.getStream(streamNumber);
        IStreamCoder coder = stream.getStreamCoder();
        if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
        	return coder.getHeight();
        }
        return -1;
	}
	public com.xuggle.xuggler.IPixelFormat.Type getVideoPixelType(int streamNumber){
        IStream stream = container.getStream(streamNumber);
        IStreamCoder coder = stream.getStreamCoder();
        return coder.getPixelType();
	}
	public double getVideoFrameRate(int streamNumber){
        IStream stream = container.getStream(streamNumber);
        IStreamCoder coder = stream.getStreamCoder();
        return coder.getFrameRate().getDouble();
	}
	
	
	public int getVideoStreamNumber(){
		for (int i=0; i<this.getNumStreams(); i++) {
			// find the stream object
            IStream stream = container.getStream(i);
            // get the pre-configured decoder that can decode this stream;
            IStreamCoder coder = stream.getStreamCoder();
            
            if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
                return i;
            }
		}
		return -1;
	}
}
Chiedo supporto per l'implementazione di public void setBit(long frame,int x,int y,boolean bitValue) che dovrebbe:
- caricare l'immagine presente nel frame indicato
- prendere il colore presente nel pixel x,y richiesto
- modificare il colore inserendo il bitValue nel LSB
- cambiare il frame del video con il nuovo con pixel modificato direttamente nel video in oggetto

20 Risposte

  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Ho scritto il seguente codice per il metodo setBit:
    
    	//frame = numero del frame dove verra' modificato il LSB
    	//x e y coordinate del pixel che verra' modificato
    	//bitValue = il valore da inserire nel LSB
    	public void setBit(long frame,int x,int y,boolean bitValue){
    		int streamNumber = getVideoStreamNumber();
    		com.xuggle.xuggler.IPixelFormat.Type pixelType = getVideoPixelType(streamNumber);
    		IStream stream = container.getStream(streamNumber);
    		IStreamCoder coder = stream.getStreamCoder();
    		
    		//prendere l'immagine
    		BufferedImage image = ??????;
    		
    		//set the LSB
    		String bits = Integer.toBinaryString(image.getRGB(x, y));
    		if (bitValue) bits = bits.replace((char) (bits.length()-1), '1');
    		else bits = bits.replace((char) (bits.length()-1), '0');
    		
    		//save the image
    		image.setRGB(x, y, Integer.parseInt(bits));
    		//save the frame in the video
    		??????
    		return;
    	}
    
    Qualcuno riesce ad aiutarmi su come sostituire le due occorrenzze ??????
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Pittuzzo ha scritto:


    		String bits = Integer.toBinaryString(image.getRGB(x, y));
    		if (bitValue) bits = bits.replace((char) (bits.length()-1), '1');
    		else bits = bits.replace((char) (bits.length()-1), '0');
    		
    		image.setRGB(x, y, Integer.parseInt(bits));
    Scusa ma ... sei consapevole che una catena di conversioni e operazioni su stringhe di questo tipo solo per modificare dei bit è assolutamente assurda, inutile oltre che estremamente pesante (e di pixel ne avrai sicuramente milioni ....) ??

    Sai usare gli operatori bitwise ( | & ^ ~ ) ? Più eventualmente gli operatori di shift (<< , >> e >>>) ?
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Aggiorno il codice col tuo consiglio, grazie!
    Ma in merito all'oggetto del thread sai come agire?
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Pittuzzo ha scritto:


    Ma in merito all'oggetto del thread sai come agire?
    Non conosco purtroppo la API che usi per i video.

    E mi sembra pure strano che per ciascun pixel vuoi/devi fare:
          int streamNumber = getVideoStreamNumber();
          com.xuggle.xuggler.IPixelFormat.Type pixelType = getVideoPixelType(streamNumber);
          IStream stream = container.getStream(streamNumber);
          IStreamCoder coder = stream.getStreamCoder();
          
          //prendere l'immagine
          BufferedImage image = ??????;
    Prima prendi l'immagine (ammesso che quella API riesca a fornirti dei BufferedImage) del frame, poi doppio ciclo for su y/x e operi sui pixel.

    Tra l'altro, hai considerato le questioni sulla compressione del video? Se l'output finale è un video in cui viene applicata una compressione "lossy" (con perdita) alle immagini, la tua steganografia va un pochino a farsi "friggere".
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    @Pituzzo, lo sai, si, che non puo' funzionare se usi un formato video compresso?
    E tutti i formati video sono compressi?

    Le tecniche stenografice sono decisamente piu' complicate di cosi': si lavora nel dominio delle frequenze.

    Quello che vuoi fare lo puoi fare solo con le immagini tiff non compresse.

    Quindi la domanda sorge spontanea: quale e' il titolo del libro su cui stai studiando?
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Prendete il seguente codice di esempio che dato un video salva una immagine per ogni SECONDS_BETWEEN_FRAMES.
    La riga #36 definisce che tipo di immagine estrarre dal video:(mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR)).

    input le variabili: SECONDS_BETWEEN_FRAMES, inputFilename e outputFilePrefix.

    Xuggler semplifica abbastanza decompressioni/conversioni altrimenti complesse.
    
    package data;
    
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    
    import com.xuggle.mediatool.IMediaReader;
    import com.xuggle.mediatool.MediaListenerAdapter;
    import com.xuggle.mediatool.ToolFactory;
    import com.xuggle.mediatool.event.IVideoPictureEvent;
    import com.xuggle.xuggler.Global;
    
    public class VideoThumbnailsExample {
        
        public static final double SECONDS_BETWEEN_FRAMES = 10;
        private static final String inputFilename = "bird.avi";
        private static final String outputFilePrefix = "mysnapshot";
        
        // The video stream index, used to ensure we display frames from one and
        // only one video stream from the media container.
        private static int mVideoStreamIndex = -1;
        
        // Time of last frame write
        private static long mLastPtsWrite = Global.NO_PTS;
        
        public static final long MICRO_SECONDS_BETWEEN_FRAMES = 
            (long)(Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);
    
        public static void main(String[] args) {
    
            IMediaReader mediaReader = ToolFactory.makeReader(inputFilename);
    
            // stipulate that we want BufferedImages created in BGR 24bit color space
            mediaReader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
            
            mediaReader.addListener(new ImageSnapListener());
    
            // read out the contents of the media file and
            // dispatch events to the attached listener
            while (mediaReader.readPacket() == null) ;
    
        }
    
        private static class ImageSnapListener extends MediaListenerAdapter {
    
            public void onVideoPicture(IVideoPictureEvent event) {
    
                if (event.getStreamIndex() != mVideoStreamIndex) {
                    // if the selected video stream id is not yet set, go ahead an
                    // select this lucky video stream
                    if (mVideoStreamIndex == -1)
                        mVideoStreamIndex = event.getStreamIndex();
                    // no need to show frames from this video stream
                    else
                        return;
                }
    
                // if uninitialized, back date mLastPtsWrite to get the very first frame
                if (mLastPtsWrite == Global.NO_PTS)
                    mLastPtsWrite = event.getTimeStamp() - MICRO_SECONDS_BETWEEN_FRAMES;
    
                // if it's time to write the next frame
                if (event.getTimeStamp() - mLastPtsWrite >= 
                        MICRO_SECONDS_BETWEEN_FRAMES) {
                                    
                    String outputFilename = dumpImageToFile(event.getImage());
    
                    // indicate file written
                    double seconds = ((double) event.getTimeStamp()) / 
                        Global.DEFAULT_PTS_PER_SECOND;
                    System.out.printf(
                            "at elapsed time of %6.3f seconds wrote: %s\n",
                            seconds, outputFilename);
    
                    // update last write time
                    mLastPtsWrite += MICRO_SECONDS_BETWEEN_FRAMES;
                }
    
            }
            
            private String dumpImageToFile(BufferedImage image) {
                try {
                    String outputFilename = outputFilePrefix + 
                         System.currentTimeMillis() + ".png";
                    ImageIO.write(image, "png", new File(outputFilename));
                    return outputFilename;
                } 
                catch (IOException e) {
                    e.printStackTrace();
                    return null;
                }
            }
    
        }
    
    }
    
    
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    migliorabile ha scritto:


    Le tecniche stenografice
    Steganografiche ... la stenografia era un'altra cosa ...
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    ...Ma diciamo che questo thread si sta riempendo di post inutili??
    C'e' qualcuno che conosce Xuggler?
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    oregon ha scritto:


    migliorabile ha scritto:


    Le tecniche stenografice
    Steganografiche ... la stenografia era un'altra cosa ...
    Che bischero che sono!

    @Pittuzzo, la domanda che mi pongo io e': ma tu hai capito bene come funziona la steGAnografia?

    Perche', se vai vedere che cosa dice il tool OpenPuff, di cui hai dato il link, relativamente ai vari formati:

    audio: non compressi
    video: quelli basati sulla compressione JPEG e modificando le DCT (le matrici 16x16 generate DOPO la compressione e usate NELLA decompressione), e DCT sta' per Discrete Cosine Transform cioe' una variante della trasformata di Fourier! Aggeggio usato per lavorare con immagini, audio e video nel dominio delle frequenze!

    Xuggler e' una banale libreria di decompressione/compressione per formati audio e video.

    Il problema, che forse stai sottovalutando, e' il seguente:

    1) hai il video
    2) lo decomprimi
    3) ha i singoli fotogrammi
    4) modifichi i fotogrammi sulla base dei pixel
    5) li comprimi con un algoritmo a perdita di informazione (lossy)
    6) hai il video modificato

    E al punto 5, il tuo lavoro va a farsi benedire!

    Ora: il tuo approccio funziona SOLO se usi una compressione senza perdita di informazione (lossless).

    Ripropongo la domanda: su che libro di testo stai studiando?


    Per quanto riguarda il tuo metodo public void setBit(long frame,int x,int y,boolean bitValue), l'implementazione e' banale:

    1) ricuperi il frame (l'esempio lo trovi qui https://github.com/artclarke/xuggle-xuggler/blob/master/src/com/xuggle/xuggler/demos/DecodeAndCaptureFrames.java)
    2) se w e' la larghezza del frame ed ogni pixel e' un byte, e buffer e' il bytearray contenente UN CANALE del frame:

    buffer[w*y+x] &= ~0x01; // pone a 0 il LSB
    buffer[w*y+x] |= bitValue ? 0x01 : 0x00; // assegna 0 o 1 al LSB in base a bitValue

    Semplice semplice.
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Pittuzzo ha scritto:


    ...Ma diciamo che questo thread si sta riempendo di post inutili??
    Addirittura ... non credi di esagerare? Rilassati ...
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    @Pituzzo se l'e' data a gambe , quando ha visto l'aria che tirava
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Nono eccomi in questi giorni ero abb impegnato e non ho acceso il pc per niente! Rieccomi
    @oregon Baci&Abbracci

    @migliorabile Grazie mille per il tempo dedicato! Comunque sto studiando da delle dispense universitarie... se hai un libro da consigliarmi te ne sarei molto grato! Anche se sono a conoscenza dei concetti che scrivi seppur non espertissimo in materia.

    In realta' puntavo ai video con frames non compressi (il mio errore) ma effettivamente il programma diventerebbe abbastanza inutile perche' questi video sono un miraggio , faccio tesoro quindi di quanto scrivi. Mi sareppe piaciuto iniziare a fare qualcosa di piu' semplice (speravo di trovare frames con bmp non compressi) per poi dedicarmi a nascondere l'informazione nei coefficenti DCT meno importanti di immagini jpeg.

    Ma mettendo da parte la steganografia (o stenografia @oregon), resta una domanda relativa a Xuggler:
    il codice che mi hai girato effettua solo degli snapshot ad un intervallo prefissato del video in input.... Praticamente fa lo stesso di quello che ho postato io MA il pezzo mancante che mi piacerebbe capire e' come salvare una immagine diversa al post di quel frame nel video (senza ripercorre tutto il file e crearne uno nuovo); ho cercato sul web ma non ho trovato nulla! sai aiutarmi?
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    Pittuzzo ha scritto:


    @oregon Baci&Abbracci
    @migliorabile Grazie mille per il tempo dedicato!
    E a me niente? .... scherzo!

    Pittuzzo ha scritto:


    Mi sareppe piaciuto iniziare a fare qualcosa di piu' semplice (speravo di trovare frames con bmp non compressi) per poi dedicarmi a nascondere l'informazione nei coefficenti DCT meno importanti di immagini jpeg.
    Suggerimento: perché allora non provi con semplici immagini? (non video) Ad esempio immagini PNG o BMP. Entrambi i formati possono essere compressi, e se c'è appunto compressione è lossless, quindi senza perdita.
    Non avresti nemmeno bisogno di librerie esterne, perché a partire da Java 1.4 esiste nel framework la API ImageIO (la classe principale è javax.imageio.ImageIO) che permette di caricare/salvare immagini. È una API "pluggabile", si possono aggiungere plugin per supportare altri formati. Il supporto al PNG è già presente di serie nel framework fin dall'inizio della API. Il BMP invece è supportato da Java 5.

    Nota in generale: per ogni pixel puoi sicuramente sfruttare il LSB del rosso e del blu e probabilmente (da provare e verificare "ad occhio") anche del verde. L'occhio umano infatti è più sensibile al verde piuttosto che al rosso/blu.
    Prova quindi a realizzare sia l'inserimento sia l'estrazione di un "messaggio" tramite steganografia su BMP/PNG. Quando ti funzionerà, potrai passare a video o quant'altro.
  • Re: Xuggler: modificare LSB nelle varie immagini di un video

    http://www.amazon.co.uk/Watermarking-Steganography-Kaufmann-Multimedia-Information/dp/0123725852
    Da cui ho studiato l'argomento.

    E' steGAnografia NON stenografia



    In generale non si puo' sostituire un singolo fotogramma in un video compresso: bisogna decodificare e ricodificare una serie di fotogrammi, perche' la compressione video non lavora sul singolo fotogramma, ma sulla differenza tra il fotogramma precedente e quello corrente.
    Insomma, e' complicato.
    Comunque Xuggler supporta sia il decoding che l'encoding. Basta studiare gli esempi, come Convert.

    Come ti e' stato consigliato: inizia con le immagini!
Devi accedere o registrarti per scrivere nel forum
20 risposte