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; 021 022import java.awt.image.BufferedImage; 023 024import com.avpkit.mediatool.event.IVideoPictureEvent; 025import com.avpkit.core.IAudioSamples; 026import com.avpkit.core.IContainer; 027import com.avpkit.core.IContainerFormat; 028import com.avpkit.core.IError; 029import com.avpkit.core.IVideoPicture; 030 031/** 032 * An {@link IMediaCoder} that reads and decodes media from an 033 * {@link IContainer}. 034 * 035 * <p> 036 * An {@link IMediaReader} opens up a media container, 037 * reads packets from it, decodes the data, and then dispatches 038 * information about the data to any registered 039 * {@link IMediaListener} objects. The main method of 040 * interest is {@link #readPacket()}. 041 * 042 * </p> 043 * <p> 044 * 045 * Here's an example of a very simple program that prints out 046 * a line when the {@link IMediaReader} decides to open a container. 047 * 048 * </p> 049 * <pre> 050 * IMediaDebugListener myListener = new MediaListenerAdapter(){ 051 * public void onOpen(IMediaGenerator pipe) { 052 * System.out.println("opened: " + ((IMediaReader)pipe).getUrl()); 053 * } 054 * }; 055 * IMediaReader reader = ToolFactory.makeReader("myinputfile.flv"); 056 * reader.addListener(myListener); 057 * while(reader.readPacket() == null) 058 * ; 059 * </pre> 060 * <p> 061 * 062 * And here's a slightly more involved example where we read 063 * a file and display it on screen in real-time: 064 * 065 * </p> 066 * <pre> 067 * IMediaReader reader = ToolFactory.makeReader("myinputfile.flv"); 068 * reader.addListener(ToolFactory.makeViewer()); 069 * while(reader.readPacket() == null) 070 * ; 071 * </pre> 072 * <p> 073 * For examples of this class in action, see the 074 * com.avpkit.mediatool.demos package. 075 * </p> 076 * @author trebor 077 * @author aclarke 078 * 079 */ 080 081public interface IMediaReader extends IMediaCoder 082{ 083 084 /** 085 * Set if the underlying media container supports adding dynamic streams. See 086 * {@link IContainer#open(String, IContainer.Type, IContainerFormat, boolean, boolean)} 087 * . The default value for this is false. 088 * 089 * <p> 090 * 091 * If set to false, the {@link IMediaReader} can assume no new streams will be 092 * added after {@link #open()} has been called, and may decide to query the 093 * entire media file to find all meta data. If true then {@link IMediaReader} 094 * will not read ahead; instead it will only query meta data for a stream when 095 * a {@link #readPacket()} returns the first packet in a new stream. Note that 096 * a {@link IMediaWriter} can only initialize itself from a 097 * {@link IMediaReader} that has this parameter set to false. 098 * 099 * </p> 100 * <p> 101 * 102 * To have an effect, the MediaReader must not have been created with an 103 * already open {@link IContainer}, and this method must be called before the 104 * first call to {@link #readPacket}. 105 * 106 * </p> 107 * 108 * @param streamsCanBeAddedDynamically true if new streams may appear at any 109 * time during a {@link #readPacket} call 110 * 111 * @throws RuntimeException if the media container is already open 112 */ 113 114 public abstract void setAddDynamicStreams(boolean streamsCanBeAddedDynamically); 115 116 /** 117 * Report if the underlying media container supports adding dynamic 118 * streams. See {@link IContainer#open(String, IContainer.Type, 119 * IContainerFormat, boolean, boolean)}. 120 * 121 * @return true if new streams can may appear at any time during a 122 * {@link #readPacket} call 123 * @see #setAddDynamicStreams(boolean) 124 */ 125 126 public abstract boolean canAddDynamicStreams(); 127 128 /** 129 * Set if the underlying media container will attempt to establish all 130 * meta data when the container is opened, which will potentially 131 * block until it has ready enough data to find all streams in a 132 * container. If false, it will only block to read a minimal header 133 * for this container format. See {@link IContainer#open(String, 134 * IContainer.Type, IContainerFormat, boolean, boolean)}. The default 135 * value for this is true. 136 * 137 * <p> 138 * 139 * To have an effect, the MediaReader must not have been created with 140 * an already open {@link IContainer}, and this method must be called 141 * before the first call to {@link #readPacket}. 142 * 143 * </p> 144 * 145 * @param queryStreamMetaData true if meta data is to be queried 146 * 147 * @throws RuntimeException if the media container is already open 148 */ 149 150 public abstract void setQueryMetaData(boolean queryStreamMetaData); 151 152 /** 153 * Report if the underlying media container will attempt to establish 154 * all meta data when the container is opened, which will potentially 155 * block until it has ready enough data to find all streams in a 156 * container. If false, it will only block to read a minimal header 157 * for this container format. See {@link IContainer#open(String, 158 * IContainer.Type, IContainerFormat, boolean, boolean)}. 159 * 160 * @return true meta data will be queried 161 * @see #setQueryMetaData(boolean) 162 */ 163 164 public abstract boolean willQueryMetaData(); 165 166 /** 167 * Should {@link IMediaReader} automatically call {@link #close()}, only if 168 * ERROR_EOF is returned from {@link #readPacket}. Otherwise {@link #close()} 169 * is automatically called when any error value is returned. The default value 170 * for this is false. 171 * 172 * @param closeOnEofOnly true if meta data is to be queried 173 * 174 * @throws RuntimeException if the media container is already open 175 */ 176 177 public abstract void setCloseOnEofOnly(boolean closeOnEofOnly); 178 179 /** 180 * Report if close will called only if ERROR_EOF is returned from 181 * {@link #readPacket}. Otherwise close is called when any error 182 * value is returned. The default value for this is false. 183 * 184 * @return true if will close on ERROR_EOF only 185 * @see #setCloseOnEofOnly(boolean) 186 */ 187 188 public abstract boolean willCloseOnEofOnly(); 189 190 /** 191 * Decodes the next packet and calls all registered {@link IMediaListener} 192 * objects. 193 * 194 * <p> 195 * 196 * If a complete {@link IVideoPicture} or {@link IAudioSamples} set are 197 * decoded, it will be dispatched to the listeners added to the media reader. 198 * 199 * </p> 200 * 201 * <p> 202 * 203 * This method will automatically call {@link #open()} if it has not 204 * already been called, and will automatically call {@link #close()} when 205 * it reads an error or end of file from the file. The default 206 * close behavior can be changed with {@link #setCloseOnEofOnly(boolean)}. 207 * 208 * </p> 209 * 210 * @return null if there are more packets to read, otherwise return an IError 211 * instance. If {@link IError#getType()} == 212 * {@link com.avpkit.core.IError.Type#ERROR_EOF} then end of file 213 * has been reached. 214 */ 215 216 public abstract IError readPacket(); 217 218 /** 219 * Asks the {@link IMediaReader} to generate {@link BufferedImage} images when 220 * calling 221 * {@link IMediaListener#onVideoPicture(IVideoPictureEvent)} 222 * . 223 * 224 * <p> 225 * NOTE: Only {@link BufferedImage#TYPE_3BYTE_BGR} is supported today. 226 * </p> 227 * 228 * <p> 229 * If set to a non-negative value, {@link IMediaReader} will resample any 230 * video data it has decoded into the right colorspace for the 231 * {@link BufferedImage}, and generate a new {@link BufferedImage} to pass in 232 * on each 233 * {@link IMediaListener#onVideoPicture(IVideoPictureEvent) 234 * } 235 * call. 236 * </p> 237 * 238 * @param bufferedImageType The buffered image type (e.g. 239 * {@link BufferedImage#TYPE_3BYTE_BGR}) you want {@link IMediaReader} 240 * to generate. Set to -1 to disable this feature. 241 * 242 * @see BufferedImage 243 */ 244 245 public abstract void setBufferedImageTypeToGenerate(int bufferedImageType); 246 247 /** 248 * Get the {@link BufferedImage} type this {@link IMediaReader} will 249 * generate. 250 * @return the type, or -1 if disabled. 251 * 252 * @see #getBufferedImageTypeToGenerate() 253 */ 254 255 public abstract int getBufferedImageTypeToGenerate(); 256 257 /** 258 * {@inheritDoc} 259 */ 260 261 public abstract IContainer getContainer(); 262 263 /** 264 * {@inheritDoc} 265 */ 266 267 public abstract String getUrl(); 268 269 /** 270 * {@inheritDoc} 271 */ 272 273 public abstract void open(); 274 275 /** 276 * {@inheritDoc} 277 */ 278 279 public abstract void close(); 280 281}