001/*******************************************************************************
002 * Copyright (c) 2024, 2026, Olivier Ayache.  All rights reserved.
003 *
004 * This file is part of AVPKit.
005 *
006 * AVPKit is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU Lesser General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * AVPKit is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with AVPKit.  If not, see <http://www.gnu.org/licenses/>.
018 *******************************************************************************/
019
020package com.avpkit.mediatool.demos;
021
022import javax.swing.JFrame;
023
024import com.avpkit.mediatool.IMediaReader;
025import com.avpkit.mediatool.ToolFactory;
026import com.avpkit.core.IError;
027import com.avpkit.core.IMetaData;
028import com.avpkit.core.IContainer;
029import com.avpkit.core.IContainerFormat;
030
031
032/**
033 * Using {@link IMediaReader}, takes a FFMPEG device driver name (ex:
034 * "video4linux2"), and a device name (ex: /dev/video0), and displays
035 * video from that device.  For example, a web camera.
036 * 
037 * <p> For example, to play the default camera on these operating
038 * systems: <ul> <li>Microsoft Windows:<pre>java -cp
039 * %XUGGLE_HOME%\share\java\jars\avpkit-core.jar
040 * com.avpkit.mediatool.demos.DisplayWebcamVideo vfwcap 0</pre></li>
041 * <li>Linux:<pre>java -cp
042 * $XUGGLE_HOME/share/java/jars/avpkit-core.jar
043 * com.avpkit.mediatool.demos.DisplayWebcamVideo video4linux2
044 * /dev/video0</pre></li> </ul> </p>
045 * 
046 * @author aclarke
047 * @author trebor
048 */
049
050public class DisplayWebcamVideo
051{
052  /**
053   * Takes a FFMPEG webcam driver name, and a device name, opens the
054   * webcam, and displays its video in a Swing window.
055   * <p>
056   * Examples of device formats are:
057   * </p>
058   * <table border="1">
059   * <thead>
060   *  <tr>
061   *  <td>OS</td>
062   *  <td>Driver Name</td>
063   *  <td>Sample Device Name</td>
064   *  </tr>
065   *  </thead>
066   *  <tbody>
067   *  <tr>
068   *  <td>Windows</td>
069   *  <td>vfwcap</td>
070   *  <td>0</td>
071   *  </tr>
072   *  <tr>
073   *  <td>Linux</td>
074   *  <td>video4linux2</td>
075   *  <td>/dev/video0</td>
076   *  </tr>
077   *  </tbody>
078   *  </table>
079   * 
080   * <p>
081   * Webcam support is very limited; you can't query what devices are
082   * available, nor can you query what their capabilities are without
083   * actually opening the device.  Sorry, but that's how FFMPEG rolls.
084   * </p>
085   * 
086   * @param args Must contain two strings: a FFMPEG driver name and a
087   *   device name (which is dependent on the FFMPEG driver).
088   */
089
090  public static void main(String[] args)
091  {
092    if (args.length != 2)
093      throw new IllegalArgumentException(
094        "must pass in a driver name and a device name");
095    
096    // create a new mr. display webcam video
097    
098    new DisplayWebcamVideo(args[0], args[1]);
099  }
100
101  /** Construct a DisplayWebcamVideo which reads and plays a video
102   * from an attached webcam.
103   * 
104   * @param driverName the name of the webcan drive
105   * @param deviceName the name of the webcan device
106   */
107
108  public DisplayWebcamVideo(String driverName, String deviceName)
109  {
110    // create a AVPKit container object
111
112    IContainer container = IContainer.make();
113
114    // tell AVPKit about the device format
115
116    IContainerFormat format = IContainerFormat.make();
117    if (format.setInputFormat(driverName) < 0)
118      throw new IllegalArgumentException(
119        "couldn't open webcam device: " + driverName);
120    
121    // devices, unlike most files, need to have parameters set in order
122    // for AVPKit to know how to configure them, for a webcam, these
123    // parameters make sense
124
125    IMetaData params = IMetaData.make();
126    
127    params.setValue("framerate", "30/1");
128    params.setValue("video_size", "320x240");
129    
130    // open the container
131
132    int retval = container.open(deviceName, IContainer.Type.READ, format,
133        false, true, params, null);
134    if (retval < 0)
135    {
136      // this little trick converts the non friendly integer return
137      // value into a slightly more friendly object to get a
138      // human-readable error name
139
140      IError error = IError.make(retval);
141      throw new IllegalArgumentException(
142        "could not open file: " + deviceName + "; Error: " + 
143        error.getDescription());
144    }      
145
146    // create a media reader to wrap that container
147
148    IMediaReader reader = ToolFactory.makeReader(container);
149    
150    // Add a media viewer that will display the video, but that exits
151    // the JVM when it is destroyed
152    reader.addListener(ToolFactory.makeViewer(true, JFrame.EXIT_ON_CLOSE));
153
154    // read out the contents of the media file, note that nothing else
155    // happens here.  action happens in the onVideoPicture() method
156    // which is called when complete video pictures are extracted from
157    // the media source.  Since we're reading from a web cam this
158    // loop will never return, but if the window is closed, the JVM is
159    // exited.
160
161    while (reader.readPacket() == null)
162      do {} while(false);
163
164  }
165
166}