mirror of
https://github.com/mirror/jdownloader.git
synced 2024-11-23 03:59:51 +00:00
RTMP:
-removed support via rtmpdump git-svn-id: svn://svn.jdownloader.org/jdownloader/trunk@45422 ebf7c1c2-ba36-0410-9fe8-c592906822b4 Former-commit-id: 7d49ac39ade1431c05e806e2b1b8907e5722cf6a
This commit is contained in:
parent
e49f7d5434
commit
3f9a8cb4b7
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -315,8 +315,6 @@ public class AboutDialog extends AbstractDialog<Integer> {
|
|||||||
stats.add(disable("Copyright \u00A9 2009-2022 JDownloader Community"));
|
stats.add(disable("Copyright \u00A9 2009-2022 JDownloader Community"));
|
||||||
stats.add(new JLabel("Java Native Access:"), "");
|
stats.add(new JLabel("Java Native Access:"), "");
|
||||||
stats.add(disable("JNA 5.9.0", "https://github.com/java-native-access/jna"));
|
stats.add(disable("JNA 5.9.0", "https://github.com/java-native-access/jna"));
|
||||||
stats.add(new JLabel("RTMP Support:"), "");
|
|
||||||
stats.add(disable("RtmpDump", "https://rtmpdump.mplayerhq.hu"));
|
|
||||||
stats.add(new JLabel("UPNP:"), "");
|
stats.add(new JLabel("UPNP:"), "");
|
||||||
stats.add(disable("Cling", "https://github.com/4thline/cling"));
|
stats.add(disable("Cling", "https://github.com/4thline/cling"));
|
||||||
stats.add(new JLabel("Extraction:"));
|
stats.add(new JLabel("Extraction:"));
|
||||||
|
@ -1,555 +0,0 @@
|
|||||||
package jd.network.rtmp;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import jd.network.rtmp.url.RtmpUrlConnection;
|
|
||||||
import jd.nutils.JDHash;
|
|
||||||
import jd.plugins.DownloadLink;
|
|
||||||
import jd.plugins.LinkStatus;
|
|
||||||
import jd.plugins.PluginException;
|
|
||||||
import jd.plugins.PluginForHost;
|
|
||||||
import jd.plugins.hoster.RTMPDownload;
|
|
||||||
|
|
||||||
import org.appwork.storage.config.JsonConfig;
|
|
||||||
import org.appwork.utils.Application;
|
|
||||||
import org.appwork.utils.Regex;
|
|
||||||
import org.appwork.utils.formatter.SizeFormatter;
|
|
||||||
import org.appwork.utils.net.throttledconnection.ThrottledConnection;
|
|
||||||
import org.appwork.utils.net.throttledconnection.ThrottledConnectionHandler;
|
|
||||||
import org.appwork.utils.os.CrossSystem;
|
|
||||||
import org.appwork.utils.speedmeter.SpeedMeterInterface;
|
|
||||||
import org.jdownloader.controlling.FileCreationManager;
|
|
||||||
import org.jdownloader.nativ.NativeProcess;
|
|
||||||
import org.jdownloader.plugins.DownloadPluginProgress;
|
|
||||||
import org.jdownloader.settings.RtmpdumpSettings;
|
|
||||||
import org.jdownloader.translate._JDT;
|
|
||||||
|
|
||||||
public class RtmpDump extends RTMPDownload {
|
|
||||||
private static class RTMPCon implements SpeedMeterInterface, ThrottledConnection {
|
|
||||||
private ThrottledConnectionHandler handler;
|
|
||||||
|
|
||||||
public ThrottledConnectionHandler getHandler() {
|
|
||||||
return handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLimit() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getValue(Resolution resolution) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putBytes(final long bytes, final long time) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetSpeedmeter() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHandler(final ThrottledConnectionHandler manager) {
|
|
||||||
handler = manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLimit(final int kpsLimit) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public long transfered() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Resolution getResolution() {
|
|
||||||
return Resolution.SECONDS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private volatile long BYTESLOADED = 0l;
|
|
||||||
private volatile long SPEED = 0l;
|
|
||||||
private float progressFloat = 0;
|
|
||||||
|
|
||||||
protected float getProgressFloat() {
|
|
||||||
return progressFloat;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int PID = -1;
|
|
||||||
private static String RTMPDUMP = null;
|
|
||||||
private static String RTMPVERSION = null;
|
|
||||||
private NativeProcess NP;
|
|
||||||
private Process P;
|
|
||||||
private InputStreamReader R;
|
|
||||||
private RtmpdumpSettings config;
|
|
||||||
|
|
||||||
public RtmpDump(final PluginForHost plugin, final DownloadLink downloadLink, final String rtmpURL) throws IOException, PluginException {
|
|
||||||
super(plugin, downloadLink, rtmpURL);
|
|
||||||
downloadable.setDownloadInterface(this);
|
|
||||||
config = JsonConfig.create(RtmpdumpSettings.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to locate a rtmpdump executable. The *nix /usr bin folders is searched first, then local tools folder. If found, the path
|
|
||||||
* will is saved to the variable RTMPDUMP.
|
|
||||||
*
|
|
||||||
* @return Whether or not rtmpdump executable was found
|
|
||||||
*/
|
|
||||||
private synchronized boolean findRtmpDump() {
|
|
||||||
String ret = RTMPDUMP;
|
|
||||||
if (ret != null) {
|
|
||||||
return ret.length() > 0;
|
|
||||||
}
|
|
||||||
if (CrossSystem.isUnix() || CrossSystem.isMac()) {
|
|
||||||
if (new File("/usr/local/bin/rtmpdump").isFile()) {
|
|
||||||
ret = "/usr/local/bin/rtmpdump";
|
|
||||||
} else if (new File("/usr/bin/rtmpdump").isFile()) {
|
|
||||||
ret = "/usr/bin/rtmpdump";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (CrossSystem.isWindows()) {
|
|
||||||
ret = Application.getResource("tools/Windows/rtmpdump/rtmpdump.exe").getAbsolutePath();
|
|
||||||
} else if (CrossSystem.isLinux() && ret == null) {
|
|
||||||
ret = Application.getResource("tools/linux/rtmpdump/rtmpdump").getAbsolutePath();
|
|
||||||
} else if (CrossSystem.isMac() && ret == null) {
|
|
||||||
ret = Application.getResource("tools/mac/rtmpdump/rtmpdump").getAbsolutePath();
|
|
||||||
}
|
|
||||||
if (ret != null && new File(ret).isFile()) {
|
|
||||||
new File(ret).setExecutable(true);
|
|
||||||
RTMPDUMP = ret;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getProcessId() {
|
|
||||||
try {
|
|
||||||
final Field pidField = P.getClass().getDeclaredField("pid");
|
|
||||||
pidField.setAccessible(true);
|
|
||||||
PID = pidField.getInt(P);
|
|
||||||
} catch (final Exception e) {
|
|
||||||
PID = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRtmpDumpChecksum() throws Exception {
|
|
||||||
if (!findRtmpDump()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return JDHash.getMD5(new File(RTMPDUMP));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempt to locate a rtmpdump executable and parse the version number from the 'rtmpdump -h' output.
|
|
||||||
*
|
|
||||||
* @return The version number of the RTMPDump executable
|
|
||||||
*/
|
|
||||||
public synchronized String getRtmpDumpVersion() throws Exception {
|
|
||||||
if (RTMPVERSION != null) {
|
|
||||||
return RTMPVERSION;
|
|
||||||
}
|
|
||||||
if (!findRtmpDump()) {
|
|
||||||
throw new PluginException(LinkStatus.ERROR_FATAL, "Error: rtmpdump executable not found!");
|
|
||||||
}
|
|
||||||
final String arg = " -h";
|
|
||||||
NativeProcess verNP = null;
|
|
||||||
Process verP = null;
|
|
||||||
InputStreamReader verR = null;
|
|
||||||
try {
|
|
||||||
if (CrossSystem.isWindows()) {
|
|
||||||
verNP = new NativeProcess(RTMPDUMP, arg);
|
|
||||||
verR = new InputStreamReader(verNP.getErrorStream());
|
|
||||||
} else {
|
|
||||||
verP = Runtime.getRuntime().exec(RTMPDUMP + arg);
|
|
||||||
verR = new InputStreamReader(verP.getErrorStream());
|
|
||||||
}
|
|
||||||
final BufferedReader br = new BufferedReader(verR);
|
|
||||||
final Pattern reg = Pattern.compile("RTMPDump v([0-9.]+)");
|
|
||||||
String line = null;
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
final Matcher match = reg.matcher(line);
|
|
||||||
if (match.find()) {
|
|
||||||
RTMPVERSION = match.group(1);
|
|
||||||
return RTMPVERSION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new PluginException(LinkStatus.ERROR_FATAL, "Error " + RTMPDUMP + " version not found!");
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
/* make sure we destroyed the process */
|
|
||||||
verP.destroy();
|
|
||||||
} catch (final Throwable e) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
/* close InputStreamReader */
|
|
||||||
verR.close();
|
|
||||||
} catch (final Throwable e) {
|
|
||||||
}
|
|
||||||
if (verNP != null) {
|
|
||||||
/* close Streams from native */
|
|
||||||
verNP.closeStreams();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getTotalLinkBytesLoadedLive() {
|
|
||||||
return BYTESLOADED;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendSIGINT() {
|
|
||||||
getProcessId();
|
|
||||||
if (PID >= 0) {
|
|
||||||
try {
|
|
||||||
Runtime.getRuntime().exec("kill -SIGINT " + String.valueOf(PID));
|
|
||||||
} catch (final Throwable e1) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void kill() {
|
|
||||||
if (CrossSystem.isWindows()) {
|
|
||||||
if (NP != null) {
|
|
||||||
NP.sendCtrlCSignal();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendSIGINT();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean FixFlv(File tmpFile) throws Exception {
|
|
||||||
FlvFixer flvfix = new FlvFixer();
|
|
||||||
flvfix.setInputFile(tmpFile);
|
|
||||||
if (config.isFlvFixerDebugModeEnabled()) {
|
|
||||||
flvfix.setDebug(true);
|
|
||||||
}
|
|
||||||
if (!flvfix.scan(dLink)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
File fixedFile = flvfix.getoutputFile();
|
|
||||||
if (!fixedFile.exists()) {
|
|
||||||
logger.severe("File " + fixedFile.getAbsolutePath() + " not found!");
|
|
||||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.downloadlink_status_error_file_not_found(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
|
||||||
}
|
|
||||||
if (!FileCreationManager.getInstance().delete(tmpFile, null)) {
|
|
||||||
logger.severe("Could not delete part file " + tmpFile);
|
|
||||||
FileCreationManager.getInstance().delete(fixedFile, null);
|
|
||||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.system_download_errors_couldnotdelete(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
|
||||||
}
|
|
||||||
if (!fixedFile.renameTo(tmpFile)) {
|
|
||||||
logger.severe("Could not rename file " + fixedFile.getName() + " to " + tmpFile.getName());
|
|
||||||
FileCreationManager.getInstance().delete(fixedFile, null);
|
|
||||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.system_download_errors_couldnotrename(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isReadPacketError(final String errorMessage) {
|
|
||||||
if (errorMessage != null) {
|
|
||||||
final String e = errorMessage.toLowerCase(Locale.ENGLISH);
|
|
||||||
return e.contains("rtmp_readpacket, failed to read rtmp packet header") || e.contains("rtmp_readpacket, failed to read RTMP packet body");
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isTimeoutError(final String errorMessage) {
|
|
||||||
if (errorMessage != null) {
|
|
||||||
final String e = errorMessage.toLowerCase(Locale.ENGLISH);
|
|
||||||
return e.contains("rtmpdump timed out while waiting for a reply after");
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean start(final RtmpUrlConnection rtmpConnection) throws Exception {
|
|
||||||
if (!findRtmpDump()) {
|
|
||||||
throw new PluginException(LinkStatus.ERROR_FATAL, "Error: rtmpdump executable not found!");
|
|
||||||
}
|
|
||||||
// rtmpe not supported
|
|
||||||
/** TODO: Add a nicer error message... */
|
|
||||||
if (rtmpConnection.protocolIsRtmpe()) {
|
|
||||||
logger.warning("Protocol rtmpe:// not supported");
|
|
||||||
throw new PluginException(LinkStatus.ERROR_FATAL, "rtmpe:// not supported!");
|
|
||||||
}
|
|
||||||
boolean debug = config.isRtmpDumpDebugModeEnabled();
|
|
||||||
if (debug) {
|
|
||||||
rtmpConnection.setVerbose();
|
|
||||||
}
|
|
||||||
final ThrottledConnection tcon = new RTMPCon() {
|
|
||||||
@Override
|
|
||||||
public long getValue(Resolution resolution) {
|
|
||||||
return SPEED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long transfered() {
|
|
||||||
return BYTESLOADED;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
final File tmpFile = new File(downloadable.getFileOutput() + ".part");
|
|
||||||
final DownloadPluginProgress downloadPluginProgress = new DownloadPluginProgress(downloadable, this, Color.GREEN.darker()) {
|
|
||||||
@Override
|
|
||||||
public long getTotal() {
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getCurrent() {
|
|
||||||
return (long) getProgressFloat();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getPercent() {
|
|
||||||
return getProgressFloat();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
getManagedConnetionHandler().addThrottledConnection(tcon);
|
|
||||||
downloadable.setConnectionHandler(getManagedConnetionHandler());
|
|
||||||
downloadable.addPluginProgress(downloadPluginProgress);
|
|
||||||
rtmpConnection.connect();
|
|
||||||
String line = "";
|
|
||||||
String error = "";
|
|
||||||
long iSize = 0;
|
|
||||||
long before = 0;
|
|
||||||
long lastTime = System.currentTimeMillis();
|
|
||||||
boolean complete = false;
|
|
||||||
long readerTimeOut = 10000l;
|
|
||||||
String cmdArgsWindows = rtmpConnection.getCommandLineParameter();
|
|
||||||
final List<String> cmdArgsMacAndLinux = new ArrayList<String>();
|
|
||||||
if (CrossSystem.isWindows()) {
|
|
||||||
// MAX_PATH Fix --> \\?\ + Path
|
|
||||||
if (String.valueOf(tmpFile).length() >= 260 || config.isWindowsPathWorkaroundEnabled()) {
|
|
||||||
// https://msdn.microsoft.com/en-us/library/aa365247.aspx
|
|
||||||
cmdArgsWindows += " \"\\\\?\\" + String.valueOf(tmpFile) + "\"";
|
|
||||||
} else {
|
|
||||||
cmdArgsWindows += " \"" + String.valueOf(tmpFile) + "\"";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cmdArgsMacAndLinux.add(RTMPDUMP);
|
|
||||||
cmdArgsMacAndLinux.addAll(rtmpConnection.getCommandLineParameterAsArray());
|
|
||||||
cmdArgsMacAndLinux.add(String.valueOf(tmpFile));
|
|
||||||
}
|
|
||||||
setResume(rtmpConnection.isResume());
|
|
||||||
final ExecutorService executor = Executors.newSingleThreadExecutor();
|
|
||||||
try {
|
|
||||||
if (CrossSystem.isWindows()) {
|
|
||||||
logger.info(cmdArgsWindows);
|
|
||||||
NP = new NativeProcess(RTMPDUMP, cmdArgsWindows);
|
|
||||||
R = new InputStreamReader(NP.getErrorStream());
|
|
||||||
} else {
|
|
||||||
logger.info(cmdArgsMacAndLinux.toString());
|
|
||||||
P = Runtime.getRuntime().exec(cmdArgsMacAndLinux.toArray(new String[cmdArgsMacAndLinux.size()]));
|
|
||||||
R = new InputStreamReader(P.getErrorStream());
|
|
||||||
}
|
|
||||||
final BufferedReader br = new BufferedReader(R);
|
|
||||||
/* prevents input buffer timed out */
|
|
||||||
Future<String> future;
|
|
||||||
Callable<String> readTask = new Callable<String>() {
|
|
||||||
@Override
|
|
||||||
public String call() throws Exception {
|
|
||||||
return br.readLine();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
long tmplen = 0, fixedlen = 0, calc = 0;
|
|
||||||
while (true) {
|
|
||||||
if (externalDownloadStop()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
future = executor.submit(readTask);
|
|
||||||
try {
|
|
||||||
if (!debug && error.isEmpty() && line.startsWith("ERROR")) {
|
|
||||||
error = line;
|
|
||||||
}
|
|
||||||
line = future.get(readerTimeOut, TimeUnit.MILLISECONDS);
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "rtmpdump timed out while waiting for a reply after " + readerTimeOut + " ms");
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
if (line == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (debug || true) {
|
|
||||||
logger.finest(line);
|
|
||||||
}
|
|
||||||
if (line.startsWith("ERROR:")) {
|
|
||||||
error = line;
|
|
||||||
}
|
|
||||||
if (!new Regex(line, "^[0-9]").matches()) {
|
|
||||||
if (line.contains("length") || line.contains("lastkeyframelocation") || line.contains("filesize")) {
|
|
||||||
String size = new Regex(line, ".*?(\\d.+)").getMatch(0);
|
|
||||||
iSize = SizeFormatter.getSize(size);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (downloadable.getDownloadTotalBytes() == 0) {
|
|
||||||
downloadable.setDownloadTotalBytes(iSize);
|
|
||||||
}
|
|
||||||
// is resumed
|
|
||||||
if (iSize == 0) {
|
|
||||||
iSize = downloadable.getDownloadTotalBytes();
|
|
||||||
}
|
|
||||||
int pos1 = line.indexOf("(");
|
|
||||||
int pos2 = line.indexOf(")");
|
|
||||||
if (line.toUpperCase().matches("\\d+\\.\\d+\\sKB\\s/\\s\\d+\\.\\d+\\sSEC(\\s\\(\\d+\\.\\d%\\))?")) {
|
|
||||||
if (pos1 != -1 && pos2 != -1) {
|
|
||||||
progressFloat = Float.parseFloat(line.substring(pos1 + 1, pos2 - 1));
|
|
||||||
} else {
|
|
||||||
progressFloat = Math.round(BYTESLOADED * 100.0F / iSize * 10) / 10.0F;
|
|
||||||
}
|
|
||||||
BYTESLOADED = SizeFormatter.getSize(line.substring(0, line.toUpperCase().indexOf("KB") + 2));
|
|
||||||
if (pos1 != -1 && pos2 != -1) {
|
|
||||||
if (progressFloat > 0.0) {
|
|
||||||
tmplen = (long) (BYTESLOADED * 100.0F / progressFloat);
|
|
||||||
fixedlen = downloadable.getDownloadTotalBytes();
|
|
||||||
calc = Math.abs(((fixedlen / 1024) - (tmplen / 1024)) % 1024);
|
|
||||||
if (calc > 768 && calc < 960) {
|
|
||||||
downloadable.setDownloadTotalBytes(tmplen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (System.currentTimeMillis() - lastTime > 1000) {
|
|
||||||
SPEED = (BYTESLOADED - before) / (System.currentTimeMillis() - lastTime) * 1000l;
|
|
||||||
lastTime = System.currentTimeMillis();
|
|
||||||
before = BYTESLOADED;
|
|
||||||
// downloadable.setChunksProgress(new long[] { BYTESLOADED });
|
|
||||||
downloadable.setDownloadBytesLoaded(BYTESLOADED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (progressFloat >= 99.8 && progressFloat < 100) {
|
|
||||||
if (line.toLowerCase().contains("download may be incomplete")) {
|
|
||||||
complete = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (line.toLowerCase().contains("couldn't resume flv file")) {
|
|
||||||
downloadable.setLinkStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (line.toLowerCase().contains("download complete")) {
|
|
||||||
// autoresuming when FMS sends NetStatus.Play.Stop and progress less than 100%
|
|
||||||
if (progressFloat < 99.8 && !line.toLowerCase().contains("download complete")) {
|
|
||||||
downloadable.setLinkStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
|
|
||||||
}
|
|
||||||
Thread.sleep(1000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
kill();
|
|
||||||
try {
|
|
||||||
downloadable.removePluginProgress(downloadPluginProgress);
|
|
||||||
executor.shutdownNow();
|
|
||||||
if (rtmpConnection != null) {
|
|
||||||
rtmpConnection.disconnect();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
/* make sure we destroyed the process */
|
|
||||||
P.destroy();
|
|
||||||
} catch (final Throwable e) {
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
/* close InputStreamReader */
|
|
||||||
R.close();
|
|
||||||
} catch (final Throwable e) {
|
|
||||||
}
|
|
||||||
if (NP != null) {
|
|
||||||
/* close Streams from native */
|
|
||||||
NP.closeStreams();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (downloadable.getLinkStatus() == LinkStatus.ERROR_DOWNLOAD_INCOMPLETE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (error.isEmpty() && line == null) {
|
|
||||||
if (dLink.getBooleanProperty("FLVFIXER", false)) {
|
|
||||||
if (!FixFlv(tmpFile)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.severe("RtmpDump: An unknown error has occured!");
|
|
||||||
throw new PluginException(LinkStatus.ERROR_RETRY);
|
|
||||||
}
|
|
||||||
if (line != null) {
|
|
||||||
if (line.toLowerCase().contains("download complete") || complete) {
|
|
||||||
downloadable.setDownloadTotalBytes(BYTESLOADED);
|
|
||||||
downloadable.setDownloadTotalBytes(BYTESLOADED);
|
|
||||||
if (dLink.getBooleanProperty("FLVFIXER", false)) {
|
|
||||||
if (!FixFlv(tmpFile)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.finest("rtmpdump: no errors -> rename");
|
|
||||||
if (!tmpFile.renameTo(new File(downloadable.getFileOutput()))) {
|
|
||||||
logger.severe("Could not rename file " + tmpFile + " to " + downloadable.getFileOutput());
|
|
||||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.system_download_errors_couldnotrename(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
|
||||||
}
|
|
||||||
downloadable.setLinkStatus(LinkStatus.FINISHED);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (error != null) {
|
|
||||||
String e = error.toLowerCase();
|
|
||||||
/* special ArteTv handling */
|
|
||||||
if (this.plg.getLazyP().getClassName().endsWith("ArteTv")) {
|
|
||||||
if (e.contains("netstream.failed")) {
|
|
||||||
if (downloadable.getDownloadTotalBytes() > 0) {
|
|
||||||
dLink.setProperty("STREAMURLISEXPIRED", true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.contains("last tag size must be greater/equal zero")) {
|
|
||||||
if (!FixFlv(tmpFile)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
|
|
||||||
} else if (isReadPacketError(e)) {
|
|
||||||
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, e);
|
|
||||||
} else if (e.contains("netstream.play.streamnotfound")) {
|
|
||||||
FileCreationManager.getInstance().delete(tmpFile, null);
|
|
||||||
throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND);
|
|
||||||
} else {
|
|
||||||
String cmd = cmdArgsWindows;
|
|
||||||
if (!CrossSystem.isWindows()) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (String s : cmdArgsMacAndLinux) {
|
|
||||||
sb.append(s);
|
|
||||||
sb.append(" ");
|
|
||||||
}
|
|
||||||
cmd = sb.toString();
|
|
||||||
}
|
|
||||||
logger.severe("cmd: " + cmd);
|
|
||||||
logger.severe(error);
|
|
||||||
throw new PluginException(LinkStatus.ERROR_FATAL, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} finally {
|
|
||||||
if (BYTESLOADED > 0) {
|
|
||||||
downloadable.setDownloadBytesLoaded(BYTESLOADED);
|
|
||||||
}
|
|
||||||
plg.setDownloadInterface(null);
|
|
||||||
downloadable.removePluginProgress(downloadPluginProgress);
|
|
||||||
getManagedConnetionHandler().removeThrottledConnection(tcon);
|
|
||||||
downloadable.removeConnectionHandler(getManagedConnetionHandler());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,496 +0,0 @@
|
|||||||
package jd.network.rtmp.url;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.SocketPermission;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.security.Permission;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.appwork.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <tt>UrlConnection</tt> for the rtmp protocol
|
|
||||||
*
|
|
||||||
* @author mike0007
|
|
||||||
* @author bismarck
|
|
||||||
*/
|
|
||||||
public class RtmpUrlConnection extends URLConnection {
|
|
||||||
|
|
||||||
private final static int DEFAULT_PORT = 1935;
|
|
||||||
|
|
||||||
// Connection Parameters
|
|
||||||
private static final String KEY_APP = "a"; // app
|
|
||||||
private static final String KEY_TC_URL = "t"; // tcUrl
|
|
||||||
private static final String KEY_PAGE_URL = "p"; // pageUrl
|
|
||||||
private static final String KEY_FLASH_VER = "f"; // flashVer
|
|
||||||
private static final String KEY_SWF_URL = "s"; // swfUrl
|
|
||||||
private static final String KEY_CONN = "C"; // conn
|
|
||||||
private static final String KEY_RTMP = "r"; // Url
|
|
||||||
private static final String KEY_PORT = "c"; // Port
|
|
||||||
private static final String KEY_PROTOCOL = "l"; // protocol
|
|
||||||
|
|
||||||
// Session Parameters
|
|
||||||
private static final String KEY_PLAYPATH = "y"; // playpath
|
|
||||||
private static final String KEY_LIVE = "v"; // live
|
|
||||||
private static final String KEY_SUBSCRIBE = "d"; // subscribe
|
|
||||||
private static final String KEY_REALTIME = "R"; // realtime
|
|
||||||
private static final String KEY_START = "A"; // start
|
|
||||||
private static final String KEY_STOP = "B"; // stop
|
|
||||||
private static final String KEY_BUFFER = "b"; // buffer
|
|
||||||
private static final String KEY_TIMEOUT = "m"; // timeout
|
|
||||||
private static final String KEY_RESUME = "e"; // resume
|
|
||||||
|
|
||||||
// Security Parameters
|
|
||||||
private static final String KEY_SWF_VFY = "W"; // swfVfy
|
|
||||||
private static final String KEY_SWF_AGE = "X"; // swfAge"
|
|
||||||
private static final String KEY_TOKEN = "T"; // token
|
|
||||||
|
|
||||||
// Network Parameters
|
|
||||||
private static final String KEY_SOCKS = "S"; // socks
|
|
||||||
|
|
||||||
// Debug Parameters
|
|
||||||
private static final String KEY_DEBUG = "z"; // debug
|
|
||||||
private static final String KEY_VERBOSE = "V"; // verbose
|
|
||||||
|
|
||||||
protected HashMap<String, String> parameterMap = null;
|
|
||||||
|
|
||||||
public HashMap<String, String> getParameterMap() {
|
|
||||||
return parameterMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* <p>
|
|
||||||
* An example character string suitable for use with RtmpDump:
|
|
||||||
* <p>
|
|
||||||
* <tt>
|
|
||||||
* "rtmp://flashserver:1935/ondemand/___the_file___"
|
|
||||||
* </tt>
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <tt>
|
|
||||||
* "<----------Host--------><--App--><--Playpath-->"
|
|
||||||
* </tt>
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* <tt>
|
|
||||||
* "<--------------TcUrl------------>"
|
|
||||||
* </tt>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* rtmp <tt>URL</tt> to the rtmp source
|
|
||||||
*/
|
|
||||||
public RtmpUrlConnection(final URL url) {
|
|
||||||
this(url, new HashMap<String, String>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* <p>
|
|
||||||
* An example character string suitable for use with RTMP_SetupURL():
|
|
||||||
* <p>
|
|
||||||
* <tt>
|
|
||||||
* "rtmp://flashserver:1935/ondemand/thefile swfUrl=http://flashserver/player.swf swfVfy=1"
|
|
||||||
* </tt>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param url
|
|
||||||
* rtmp <tt>URL</tt> to the rtmp source
|
|
||||||
* @param parameterMap
|
|
||||||
* <tt>HashMap</tt> with parameters for the stream
|
|
||||||
*/
|
|
||||||
public RtmpUrlConnection(final URL url, final HashMap<String, String> parameterMap) {
|
|
||||||
super(url);
|
|
||||||
this.parameterMap = parameterMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a communications link to the resource referenced by this URL, if such a connection has not already been established.
|
|
||||||
* <p>
|
|
||||||
* If the <code>connect</code> method is called when the connection has already been opened (indicated by the <code>connected</code>
|
|
||||||
* field having the value <code>true</code>), the call is ignored.
|
|
||||||
* <p>
|
|
||||||
* URLConnection objects go through two phases: first they are created, then they are connected. After being created, and before being
|
|
||||||
* connected, various options can be specified (e.g., doInput and UseCaches). After connecting, it is an error to try to set them.
|
|
||||||
* Operations that depend on being connected, like getContentLength, will implicitly perform the connection, if necessary.
|
|
||||||
*
|
|
||||||
* @throws SocketTimeoutException
|
|
||||||
* if the timeout expires before the connection can be established
|
|
||||||
* @exception IOException
|
|
||||||
* if an I/O error occurs while opening the connection.
|
|
||||||
* @see java.net.URLConnection#connected
|
|
||||||
* @see #getConnectTimeout()
|
|
||||||
* @see #setConnectTimeout(int)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void connect() throws IOException {
|
|
||||||
connected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates that other requests to the server are unlikely in the near future. Calling disconnect() should not imply that this
|
|
||||||
* RtmpURLConnection instance can be reused for other requests.
|
|
||||||
*/
|
|
||||||
public void disconnect() {
|
|
||||||
connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create command line parameters for Windows.
|
|
||||||
*/
|
|
||||||
public String getCommandLineParameter() {
|
|
||||||
final StringBuilder cmdargs = new StringBuilder("");
|
|
||||||
String ret = null;
|
|
||||||
if (parameterMap != null) {
|
|
||||||
final Iterator<String> keyIter = parameterMap.keySet().iterator();
|
|
||||||
while (keyIter.hasNext()) {
|
|
||||||
final String key = keyIter.next();
|
|
||||||
if (parameterMap.get(key) != null) {
|
|
||||||
if (KEY_CONN.equals(key)) { // example: -C B:0 -C S:String -C N:1234
|
|
||||||
for (String s : parameterMap.get(key).split("#")) {
|
|
||||||
cmdargs.append(" -").append(key).append(" " + s);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cmdargs.append(" -").append(key).append(" \"").append(parameterMap.get(key)).append("\"");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cmdargs.append(" -").append(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = cmdargs.toString() + " -o";
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create command line parameters for Uni*.
|
|
||||||
*/
|
|
||||||
public List<String> getCommandLineParameterAsArray() {
|
|
||||||
List<String> cmdargs = new ArrayList<String>();
|
|
||||||
if (parameterMap != null) {
|
|
||||||
final Iterator<String> keyIter = parameterMap.keySet().iterator();
|
|
||||||
while (keyIter.hasNext()) {
|
|
||||||
final String key = keyIter.next();
|
|
||||||
if (parameterMap.get(key) != null) {
|
|
||||||
if (KEY_CONN.equals(key)) { // example: -C B:0 -C S:String -C N:1234
|
|
||||||
for (String s : parameterMap.get(key).split("#")) {
|
|
||||||
cmdargs.add("-" + key);
|
|
||||||
cmdargs.add(s);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cmdargs.add("-" + key);
|
|
||||||
cmdargs.add(parameterMap.get(key));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cmdargs.add("-" + key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cmdargs.add("-o");
|
|
||||||
}
|
|
||||||
return cmdargs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the <code>content-length</code>.
|
|
||||||
*
|
|
||||||
* @return the content length of the resource that this connection's URL references, or <code>-1</code> if the content length is not
|
|
||||||
* known.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int getContentLength() {
|
|
||||||
// Use RTMP_GetDuration and recalculate the seconds to byte!?
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the <code>content-type</code>.
|
|
||||||
*
|
|
||||||
* @return the content type of the resource that the URL references, or <code>null</code> if not known.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String getContentType() {
|
|
||||||
// For now we don't know which content we have
|
|
||||||
// For the future one of these may be right (adobe stuff)
|
|
||||||
|
|
||||||
// File extension:
|
|
||||||
// .flv
|
|
||||||
// .f4v
|
|
||||||
// .f4p
|
|
||||||
// .f4a
|
|
||||||
// .f4b
|
|
||||||
|
|
||||||
// Internet media type:
|
|
||||||
// video/x-flv
|
|
||||||
// video/mp4
|
|
||||||
// video/x-m4v
|
|
||||||
// audio/mp4a-latm
|
|
||||||
// video/3gpp
|
|
||||||
// video/quicktime
|
|
||||||
// audio/mp4
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Permission getPermission() throws IOException {
|
|
||||||
int port = url.getPort();
|
|
||||||
port = port < 0 ? DEFAULT_PORT : port;
|
|
||||||
final String host = url.getHost() + ":" + port;
|
|
||||||
final Permission permission = new SocketPermission(host, "connect");
|
|
||||||
return permission;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of application to connect to on the RTMP server. Overrides the app in the RTMP URL. Sometimes the librtmp URL parser cannot
|
|
||||||
* determine the app name automatically, so it must be given explicitly using this option.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setApp(final String value) {
|
|
||||||
parameterMap.put(KEY_APP, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set buffer time to num milliseconds. The default is 36000000.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setBuffer(final int value) {
|
|
||||||
parameterMap.put(KEY_BUFFER, String.valueOf(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Append arbitrary AMF data to the Connect message. The type must be B for Boolean, N for number, S for string, O for object, or Z for
|
|
||||||
* null. For Booleans the data must be either 0 or 1 for FALSE or TRUE, respectively. Likewise for Objects the data must be 0 or 1 to
|
|
||||||
* end or begin an object, respectively. Data items in subobjects may be named, by prefixing the type with 'N' and specifying the name
|
|
||||||
* before the value, e.g. NB:myFlag:1. This option may be used multiple times to construct arbitrary AMF sequences. E.g.
|
|
||||||
* <p>
|
|
||||||
* <tt>
|
|
||||||
* conn=B:1 conn=S:authMe conn=O:1 conn=NN:code:1.23 conn=NS:flag:ok conn=O:0
|
|
||||||
* </tt>
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setConn(final String value) {
|
|
||||||
if (parameterMap.containsKey(KEY_CONN)) {
|
|
||||||
parameterMap.put(KEY_CONN, parameterMap.get(KEY_CONN) + "#" + value);
|
|
||||||
} else {
|
|
||||||
parameterMap.put(KEY_CONN, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Debug level command output.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void setDebug() {
|
|
||||||
parameterMap.put(KEY_DEBUG, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Version of the Flash plugin used to run the SWF player. The default is "LNX 10,0,32,18".
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setFlashVer(final String value) {
|
|
||||||
parameterMap.put(KEY_FLASH_VER, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify that the media is a live stream. No resuming or seeking in live streams is possible.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setLive(final boolean value) {
|
|
||||||
parameterMap.put(KEY_LIVE, (value ? "1" : "0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL of the web page in which the media was embedded. By default no value will be sent.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setPageUrl(final String value) {
|
|
||||||
parameterMap.put(KEY_PAGE_URL, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the playpath parsed from the RTMP URL. Sometimes the rtmpdump URL parser cannot determine the correct playpath
|
|
||||||
* automatically, so it must be given explicitly using this option.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setPlayPath(final String value) {
|
|
||||||
parameterMap.put(KEY_PLAYPATH, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the port in the rtmp url.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setPort(final int value) {
|
|
||||||
parameterMap.put(KEY_PORT, String.valueOf(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overrides the protocol in the rtmp url.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* (0 - RTMP, 3 - RTMPE)
|
|
||||||
*/
|
|
||||||
public void setProtocol(final int value) {
|
|
||||||
if (value == 0 || value == 3) {
|
|
||||||
parameterMap.put(KEY_PROTOCOL, String.valueOf(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resume an incomplete RTMP download.
|
|
||||||
*
|
|
||||||
* @param boolean
|
|
||||||
*/
|
|
||||||
public void setResume(final boolean value) {
|
|
||||||
if (value) {
|
|
||||||
parameterMap.put(KEY_RESUME, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isResume() {
|
|
||||||
return parameterMap.containsKey(KEY_RESUME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the specified SOCKS proxy.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* host:port
|
|
||||||
*/
|
|
||||||
public void setSocks(final String value) {
|
|
||||||
parameterMap.put(KEY_SOCKS, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start at num seconds into the stream. Not valid for live streams.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setStart(final int value) {
|
|
||||||
parameterMap.put(KEY_START, String.valueOf(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop at num seconds into the stream.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setStop(final int value) {
|
|
||||||
parameterMap.put(KEY_STOP, String.valueOf(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of live stream to subscribe to. Defaults to playpath.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setSubscribe(final String value) {
|
|
||||||
parameterMap.put(KEY_SUBSCRIBE, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't attempt to speed up download via the Pause/Unpause BUFX hack
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setRealTime() {
|
|
||||||
parameterMap.put(KEY_REALTIME, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify how many days to use the cached SWF info before re-checking. Use 0 to always check the SWF URL. Note that if the check shows
|
|
||||||
* that the SWF file has the same modification timestamp as before, it will not be retrieved again.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setSwfAge(final String value) {
|
|
||||||
parameterMap.put(KEY_SWF_AGE, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL of the SWF player for the media. By default no value will be sent.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setSwfUrl(final String value) {
|
|
||||||
parameterMap.put(KEY_SWF_URL, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL to player swf file, compute hash/size automatically.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setSwfVfy(final String value) {
|
|
||||||
parameterMap.put(KEY_SWF_VFY, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL of the target stream. Defaults to rtmp[t][e|s]://host[:port]/app.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setTcUrl(final String value) {
|
|
||||||
parameterMap.put(KEY_TC_URL, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timeout the session after num seconds without receiving any data from the server. The default is 120.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setTimeOut(final int value) {
|
|
||||||
parameterMap.put(KEY_TIMEOUT, String.valueOf(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key for SecureToken response, used if the server requires SecureToken authentication.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setToken(final String value) {
|
|
||||||
parameterMap.put(KEY_TOKEN, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL (e.g. rtmp[t][e|s]://hostname[:port]/app/).
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
*/
|
|
||||||
public void setUrl(final String value) {
|
|
||||||
parameterMap.put(KEY_RTMP, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean protocolIsRtmpe() {
|
|
||||||
final String url = parameterMap.get(KEY_RTMP);
|
|
||||||
if (url != null) {
|
|
||||||
if (StringUtils.startsWithCaseInsensitive(url, "rtmpe")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verbose command output.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void setVerbose() {
|
|
||||||
parameterMap.put(KEY_VERBOSE, null);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package jd.plugins.components;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.net.URLStreamHandler;
|
|
||||||
|
|
||||||
import jd.network.rtmp.url.RtmpUrlConnection;
|
|
||||||
|
|
||||||
public class RTMPStreamHandler extends URLStreamHandler {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected URLConnection openConnection(URL url) throws IOException {
|
|
||||||
return new RtmpUrlConnection(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -23,18 +23,6 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.appwork.storage.JSonStorage;
|
|
||||||
import org.appwork.storage.TypeRef;
|
|
||||||
import org.appwork.uio.ConfirmDialogInterface;
|
|
||||||
import org.appwork.uio.UIOManager;
|
|
||||||
import org.appwork.utils.Application;
|
|
||||||
import org.appwork.utils.StringUtils;
|
|
||||||
import org.appwork.utils.os.CrossSystem;
|
|
||||||
import org.appwork.utils.swing.dialog.ConfirmDialog;
|
|
||||||
import org.jdownloader.controlling.ffmpeg.json.StreamInfo;
|
|
||||||
import org.jdownloader.downloader.hls.HLSDownloader;
|
|
||||||
import org.jdownloader.plugins.components.hls.HlsContainer;
|
|
||||||
|
|
||||||
import jd.PluginWrapper;
|
import jd.PluginWrapper;
|
||||||
import jd.config.ConfigContainer;
|
import jd.config.ConfigContainer;
|
||||||
import jd.config.ConfigEntry;
|
import jd.config.ConfigEntry;
|
||||||
@ -56,9 +44,20 @@ import jd.plugins.Plugin;
|
|||||||
import jd.plugins.PluginException;
|
import jd.plugins.PluginException;
|
||||||
import jd.plugins.PluginForHost;
|
import jd.plugins.PluginForHost;
|
||||||
import jd.plugins.decrypter.DailyMotionComDecrypter;
|
import jd.plugins.decrypter.DailyMotionComDecrypter;
|
||||||
import jd.plugins.download.DownloadInterface;
|
|
||||||
import jd.utils.locale.JDL;
|
import jd.utils.locale.JDL;
|
||||||
|
|
||||||
|
import org.appwork.storage.JSonStorage;
|
||||||
|
import org.appwork.storage.TypeRef;
|
||||||
|
import org.appwork.uio.ConfirmDialogInterface;
|
||||||
|
import org.appwork.uio.UIOManager;
|
||||||
|
import org.appwork.utils.Application;
|
||||||
|
import org.appwork.utils.StringUtils;
|
||||||
|
import org.appwork.utils.os.CrossSystem;
|
||||||
|
import org.appwork.utils.swing.dialog.ConfirmDialog;
|
||||||
|
import org.jdownloader.controlling.ffmpeg.json.StreamInfo;
|
||||||
|
import org.jdownloader.downloader.hls.HLSDownloader;
|
||||||
|
import org.jdownloader.plugins.components.hls.HlsContainer;
|
||||||
|
|
||||||
@HostPlugin(revision = "$Revision$", interfaceVersion = 2, names = { "dailymotion.com" }, urls = { "https?://dailymotiondecrypted\\.com/video/\\w+" })
|
@HostPlugin(revision = "$Revision$", interfaceVersion = 2, names = { "dailymotion.com" }, urls = { "https?://dailymotiondecrypted\\.com/video/\\w+" })
|
||||||
public class DailyMotionCom extends PluginForHost {
|
public class DailyMotionCom extends PluginForHost {
|
||||||
public String getVideosource(final Browser br, final String videoID) throws Exception {
|
public String getVideosource(final Browser br, final String videoID) throws Exception {
|
||||||
@ -253,11 +252,7 @@ public class DailyMotionCom extends PluginForHost {
|
|||||||
dl = new HLSDownloader(downloadLink, br, this.dllink);
|
dl = new HLSDownloader(downloadLink, br, this.dllink);
|
||||||
dl.startDownload();
|
dl.startDownload();
|
||||||
} else if (dllink.startsWith("rtmp")) {
|
} else if (dllink.startsWith("rtmp")) {
|
||||||
downloadLink.setFinalFileName(getFormattedFilename(downloadLink));
|
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
|
||||||
String[] stream = dllink.split("@");
|
|
||||||
dl = new RTMPDownload(this, downloadLink, stream[0]);
|
|
||||||
setupRTMPConnection(stream, dl);
|
|
||||||
((RTMPDownload) dl).startDownload();
|
|
||||||
} else {
|
} else {
|
||||||
downloadDirect(downloadLink);
|
downloadDirect(downloadLink);
|
||||||
}
|
}
|
||||||
@ -503,13 +498,6 @@ public class DailyMotionCom extends PluginForHost {
|
|||||||
return dl.getBooleanProperty("type_subtitle", false);
|
return dl.getBooleanProperty("type_subtitle", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupRTMPConnection(String[] stream, DownloadInterface dl) {
|
|
||||||
jd.network.rtmp.url.RtmpUrlConnection rtmp = ((RTMPDownload) dl).getRtmpConnection();
|
|
||||||
rtmp.setUrl(stream[0]);
|
|
||||||
rtmp.setSwfVfy(stream[1]);
|
|
||||||
rtmp.setResume(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Browser prepBrowser(final Browser br) {
|
public static Browser prepBrowser(final Browser br) {
|
||||||
br.getHeaders().put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0");
|
br.getHeaders().put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0");
|
||||||
br.getHeaders().put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
br.getHeaders().put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||||
|
@ -1,93 +0,0 @@
|
|||||||
package jd.plugins.hoster;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import jd.http.Request;
|
|
||||||
import jd.network.rtmp.RtmpDump;
|
|
||||||
import jd.network.rtmp.url.RtmpUrlConnection;
|
|
||||||
import jd.plugins.DownloadLink;
|
|
||||||
import jd.plugins.LinkStatus;
|
|
||||||
import jd.plugins.PluginException;
|
|
||||||
import jd.plugins.PluginForHost;
|
|
||||||
import jd.plugins.components.RTMPStreamHandler;
|
|
||||||
import jd.plugins.download.RAFDownload;
|
|
||||||
|
|
||||||
/* Old librtmp handling in revision < 13938 */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a wrapper for RTMP
|
|
||||||
*
|
|
||||||
* @author thomas
|
|
||||||
* @author bismarck
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class RTMPDownload extends RAFDownload {
|
|
||||||
|
|
||||||
protected final RtmpUrlConnection rtmpConnection;
|
|
||||||
|
|
||||||
private final URL url;
|
|
||||||
// don't name it plugin!
|
|
||||||
protected final PluginForHost plg;
|
|
||||||
// don't name it downloadLink
|
|
||||||
protected final DownloadLink dLink;
|
|
||||||
|
|
||||||
public RTMPDownload(final PluginForHost plugin, final DownloadLink downloadLink, final String rtmpURL) throws IOException, PluginException {
|
|
||||||
super(plugin, downloadLink, null);
|
|
||||||
this.plg = plugin;
|
|
||||||
this.dLink = downloadLink;
|
|
||||||
url = new URL(null, rtmpURL, new RTMPStreamHandler());
|
|
||||||
rtmpConnection = new RtmpUrlConnection(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitialRequest(Request initialRequest) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public RtmpUrlConnection getRtmpConnection() {
|
|
||||||
return rtmpConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean startDownload() throws Exception {
|
|
||||||
/*
|
|
||||||
* Remove/replace chars which will cause rtmpdump to fail to find our download destination! TODO: Invalid download destination will
|
|
||||||
* cause plugin defect - maybe catch this and show invalid download path instead!
|
|
||||||
*/
|
|
||||||
String finalfilename = this.plg.getDownloadLink().getFinalFileName();
|
|
||||||
if (finalfilename == null) {
|
|
||||||
finalfilename = this.plg.getDownloadLink().getName();
|
|
||||||
}
|
|
||||||
finalfilename = finalfilename.replace("⁄", "_");
|
|
||||||
this.plg.getDownloadLink().setFinalFileName(finalfilename);
|
|
||||||
long before = 0;
|
|
||||||
while (!externalDownloadStop()) {
|
|
||||||
before = Math.max(before, downloadable.getDownloadBytesLoaded());
|
|
||||||
final RtmpDump rtmpDump = rtmpDump();
|
|
||||||
try {
|
|
||||||
return rtmpDump.start(rtmpConnection);
|
|
||||||
} catch (PluginException e) {
|
|
||||||
logger.log(e);
|
|
||||||
if (e.getLinkStatus() == LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE && (rtmpDump.isReadPacketError(e.getMessage()) || rtmpDump.isTimeoutError(e.getMessage()))) {
|
|
||||||
if (downloadable.getDownloadBytesLoaded() > before && rtmpConnection.isResume()) {
|
|
||||||
Thread.sleep(1000);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRtmpDumpChecksum() throws Exception {
|
|
||||||
return rtmpDump().getRtmpDumpChecksum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRtmpDumpVersion() throws Exception {
|
|
||||||
return rtmpDump().getRtmpDumpVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
private RtmpDump rtmpDump() throws Exception {
|
|
||||||
return new RtmpDump(plg, dLink, String.valueOf(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Binary file not shown.
@ -1,3 +0,0 @@
|
|||||||
# with redirect support and other improvements
|
|
||||||
#
|
|
||||||
# https://github.com/svnpenn/rtmpdump
|
|
@ -1,524 +0,0 @@
|
|||||||
/* Getopt for Microsoft C
|
|
||||||
This code is a modification of the Free Software Foundation, Inc.
|
|
||||||
Getopt library for parsing command line argument the purpose was
|
|
||||||
to provide a Microsoft Visual C friendly derivative. This code
|
|
||||||
provides functionality for both Unicode and Multibyte builds.
|
|
||||||
|
|
||||||
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
|
|
||||||
Version: 1.0
|
|
||||||
Comment: Supports getopt, getopt_long, and getopt_long_only
|
|
||||||
and POSIXLY_CORRECT environment flag
|
|
||||||
License: LGPL
|
|
||||||
|
|
||||||
Revisions:
|
|
||||||
|
|
||||||
02/03/2011 - Ludvik Jerabek - Initial Release
|
|
||||||
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
|
|
||||||
|
|
||||||
**DISCLAIMER**
|
|
||||||
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
|
|
||||||
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
|
|
||||||
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
|
|
||||||
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
|
|
||||||
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
|
|
||||||
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
|
|
||||||
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
|
|
||||||
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _CRT_SECURE_NO_WARNINGS
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "getopt.h"
|
|
||||||
|
|
||||||
enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
|
|
||||||
|
|
||||||
struct _getopt_data
|
|
||||||
{
|
|
||||||
int optind;
|
|
||||||
int opterr;
|
|
||||||
int optopt;
|
|
||||||
TCHAR *optarg;
|
|
||||||
int __initialized;
|
|
||||||
TCHAR *__nextchar;
|
|
||||||
int __ordering;
|
|
||||||
int __posixly_correct;
|
|
||||||
int __first_nonopt;
|
|
||||||
int __last_nonopt;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct _getopt_data getopt_data;
|
|
||||||
|
|
||||||
TCHAR *optarg;
|
|
||||||
|
|
||||||
int optind = 1;
|
|
||||||
int opterr = 1;
|
|
||||||
int optopt = _T('?');
|
|
||||||
|
|
||||||
static void exchange(TCHAR **argv, struct _getopt_data *d)
|
|
||||||
{
|
|
||||||
int bottom = d->__first_nonopt;
|
|
||||||
int middle = d->__last_nonopt;
|
|
||||||
int top = d->optind;
|
|
||||||
TCHAR *tem;
|
|
||||||
while (top > middle && middle > bottom)
|
|
||||||
{
|
|
||||||
if (top - middle > middle - bottom)
|
|
||||||
{
|
|
||||||
int len = middle - bottom;
|
|
||||||
register int i;
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
tem = argv[bottom + i];
|
|
||||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
|
||||||
argv[top - (middle - bottom) + i] = tem;
|
|
||||||
}
|
|
||||||
top -= len;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int len = top - middle;
|
|
||||||
register int i;
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
tem = argv[bottom + i];
|
|
||||||
argv[bottom + i] = argv[middle + i];
|
|
||||||
argv[middle + i] = tem;
|
|
||||||
}
|
|
||||||
bottom += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d->__first_nonopt += (d->optind - d->__last_nonopt);
|
|
||||||
d->__last_nonopt = d->optind;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const TCHAR *_getopt_initialize (const TCHAR *optstring, struct _getopt_data *d, int posixly_correct)
|
|
||||||
{
|
|
||||||
d->__first_nonopt = d->__last_nonopt = d->optind;
|
|
||||||
d->__nextchar = NULL;
|
|
||||||
d->__posixly_correct = posixly_correct | !!_tgetenv(_T("POSIXLY_CORRECT"));
|
|
||||||
|
|
||||||
|
|
||||||
if (optstring[0] == _T('-'))
|
|
||||||
{
|
|
||||||
d->__ordering = RETURN_IN_ORDER;
|
|
||||||
++optstring;
|
|
||||||
}
|
|
||||||
else if (optstring[0] == _T('+'))
|
|
||||||
{
|
|
||||||
d->__ordering = REQUIRE_ORDER;
|
|
||||||
++optstring;
|
|
||||||
}
|
|
||||||
else if (d->__posixly_correct)
|
|
||||||
d->__ordering = REQUIRE_ORDER;
|
|
||||||
else
|
|
||||||
d->__ordering = PERMUTE;
|
|
||||||
return optstring;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getopt_internal_r (int argc, TCHAR *const *argv, const TCHAR *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int posixly_correct)
|
|
||||||
{
|
|
||||||
int print_errors = d->opterr;
|
|
||||||
|
|
||||||
if (argc < 1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
d->optarg = NULL;
|
|
||||||
|
|
||||||
if (d->optind == 0 || !d->__initialized)
|
|
||||||
{
|
|
||||||
if (d->optind == 0)
|
|
||||||
d->optind = 1;
|
|
||||||
optstring = _getopt_initialize (optstring, d, posixly_correct);
|
|
||||||
d->__initialized = 1;
|
|
||||||
}
|
|
||||||
else if (optstring[0] == _T('-') || optstring[0] == _T('+'))
|
|
||||||
optstring++;
|
|
||||||
if (optstring[0] == _T(':'))
|
|
||||||
print_errors = 0;
|
|
||||||
|
|
||||||
if (d->__nextchar == NULL || *d->__nextchar == _T('\0'))
|
|
||||||
{
|
|
||||||
if (d->__last_nonopt > d->optind)
|
|
||||||
d->__last_nonopt = d->optind;
|
|
||||||
if (d->__first_nonopt > d->optind)
|
|
||||||
d->__first_nonopt = d->optind;
|
|
||||||
|
|
||||||
if (d->__ordering == PERMUTE)
|
|
||||||
{
|
|
||||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
|
||||||
exchange ((TCHAR **) argv, d);
|
|
||||||
else if (d->__last_nonopt != d->optind)
|
|
||||||
d->__first_nonopt = d->optind;
|
|
||||||
|
|
||||||
while (d->optind < argc && (argv[d->optind][0] != _T('-') || argv[d->optind][1] == _T('\0')))
|
|
||||||
d->optind++;
|
|
||||||
d->__last_nonopt = d->optind;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->optind != argc && !_tcscmp(argv[d->optind], _T("--")))
|
|
||||||
{
|
|
||||||
d->optind++;
|
|
||||||
|
|
||||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
|
||||||
exchange ((TCHAR **) argv, d);
|
|
||||||
else if (d->__first_nonopt == d->__last_nonopt)
|
|
||||||
d->__first_nonopt = d->optind;
|
|
||||||
d->__last_nonopt = argc;
|
|
||||||
|
|
||||||
d->optind = argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->optind == argc)
|
|
||||||
{
|
|
||||||
if (d->__first_nonopt != d->__last_nonopt)
|
|
||||||
d->optind = d->__first_nonopt;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((argv[d->optind][0] != _T('-') || argv[d->optind][1] == _T('\0')))
|
|
||||||
{
|
|
||||||
if (d->__ordering == REQUIRE_ORDER)
|
|
||||||
return -1;
|
|
||||||
d->optarg = argv[d->optind++];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == _T('-')));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (longopts != NULL && (argv[d->optind][1] == _T('-') || (long_only && (argv[d->optind][2] || !_tcschr(optstring, argv[d->optind][1])))))
|
|
||||||
{
|
|
||||||
TCHAR *nameend;
|
|
||||||
const struct option *p;
|
|
||||||
const struct option *pfound = NULL;
|
|
||||||
int exact = 0;
|
|
||||||
int ambig = 0;
|
|
||||||
int indfound = -1;
|
|
||||||
int option_index;
|
|
||||||
|
|
||||||
for (nameend = d->__nextchar; *nameend && *nameend != _T('='); nameend++);
|
|
||||||
|
|
||||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
|
||||||
if (!_tcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
|
|
||||||
{
|
|
||||||
if ((unsigned int)(nameend - d->__nextchar) == (unsigned int)_tcslen(p->name))
|
|
||||||
{
|
|
||||||
pfound = p;
|
|
||||||
indfound = option_index;
|
|
||||||
exact = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (pfound == NULL)
|
|
||||||
{
|
|
||||||
pfound = p;
|
|
||||||
indfound = option_index;
|
|
||||||
}
|
|
||||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
|
||||||
ambig = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ambig && !exact)
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr, _T("%s: option '%s' is ambiguous\n"),
|
|
||||||
argv[0], argv[d->optind]);
|
|
||||||
}
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
d->optind++;
|
|
||||||
d->optopt = 0;
|
|
||||||
return _T('?');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pfound != NULL)
|
|
||||||
{
|
|
||||||
option_index = indfound;
|
|
||||||
d->optind++;
|
|
||||||
if (*nameend)
|
|
||||||
{
|
|
||||||
if (pfound->has_arg)
|
|
||||||
d->optarg = nameend + 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
if (argv[d->optind - 1][1] == _T('-'))
|
|
||||||
{
|
|
||||||
_ftprintf(stderr, _T("%s: option '--%s' doesn't allow an argument\n"),argv[0], pfound->name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_ftprintf(stderr, _T("%s: option '%c%s' doesn't allow an argument\n"),argv[0], argv[d->optind - 1][0],pfound->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
|
|
||||||
d->optopt = pfound->val;
|
|
||||||
return _T('?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pfound->has_arg == 1)
|
|
||||||
{
|
|
||||||
if (d->optind < argc)
|
|
||||||
d->optarg = argv[d->optind++];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr,_T("%s: option '--%s' requires an argument\n"),argv[0], pfound->name);
|
|
||||||
}
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
d->optopt = pfound->val;
|
|
||||||
return optstring[0] == _T(':') ? _T(':') : _T('?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
if (longind != NULL)
|
|
||||||
*longind = option_index;
|
|
||||||
if (pfound->flag)
|
|
||||||
{
|
|
||||||
*(pfound->flag) = pfound->val;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return pfound->val;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!long_only || argv[d->optind][1] == _T('-') || _tcschr(optstring, *d->__nextchar) == NULL)
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
if (argv[d->optind][1] == _T('-'))
|
|
||||||
{
|
|
||||||
/* --option */
|
|
||||||
_ftprintf(stderr, _T("%s: unrecognized option '--%s'\n"),argv[0], d->__nextchar);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* +option or -option */
|
|
||||||
_ftprintf(stderr, _T("%s: unrecognized option '%c%s'\n"),argv[0], argv[d->optind][0], d->__nextchar);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
d->__nextchar = (TCHAR *) "";
|
|
||||||
d->optind++;
|
|
||||||
d->optopt = 0;
|
|
||||||
return _T('?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
TCHAR c = *d->__nextchar++;
|
|
||||||
TCHAR *temp = (TCHAR*)_tcschr(optstring, c);
|
|
||||||
|
|
||||||
if (*d->__nextchar == _T('\0'))
|
|
||||||
++d->optind;
|
|
||||||
|
|
||||||
if (temp == NULL || c == _T(':') || c == _T(';'))
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr, _T("%s: invalid option -- '%c'\n"), argv[0], c);
|
|
||||||
}
|
|
||||||
d->optopt = c;
|
|
||||||
return _T('?');
|
|
||||||
}
|
|
||||||
if (temp[0] == _T('W') && temp[1] == _T(';'))
|
|
||||||
{
|
|
||||||
TCHAR *nameend;
|
|
||||||
const struct option *p;
|
|
||||||
const struct option *pfound = NULL;
|
|
||||||
int exact = 0;
|
|
||||||
int ambig = 0;
|
|
||||||
int indfound = 0;
|
|
||||||
int option_index;
|
|
||||||
|
|
||||||
if (*d->__nextchar != _T('\0'))
|
|
||||||
{
|
|
||||||
d->optarg = d->__nextchar;
|
|
||||||
d->optind++;
|
|
||||||
}
|
|
||||||
else if (d->optind == argc)
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr,
|
|
||||||
_T("%s: option requires an argument -- '%c'\n"),
|
|
||||||
argv[0], c);
|
|
||||||
}
|
|
||||||
d->optopt = c;
|
|
||||||
if (optstring[0] == _T(':'))
|
|
||||||
c = _T(':');
|
|
||||||
else
|
|
||||||
c = _T('?');
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d->optarg = argv[d->optind++];
|
|
||||||
|
|
||||||
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != _T('='); nameend++);
|
|
||||||
|
|
||||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
|
||||||
if (!_tcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
|
|
||||||
{
|
|
||||||
if ((unsigned int) (nameend - d->__nextchar) == _tcslen(p->name))
|
|
||||||
{
|
|
||||||
pfound = p;
|
|
||||||
indfound = option_index;
|
|
||||||
exact = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (pfound == NULL)
|
|
||||||
{
|
|
||||||
pfound = p;
|
|
||||||
indfound = option_index;
|
|
||||||
}
|
|
||||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
|
||||||
ambig = 1;
|
|
||||||
}
|
|
||||||
if (ambig && !exact)
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr, _T("%s: option '-W %s' is ambiguous\n"),
|
|
||||||
argv[0], d->optarg);
|
|
||||||
}
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
d->optind++;
|
|
||||||
return _T('?');
|
|
||||||
}
|
|
||||||
if (pfound != NULL)
|
|
||||||
{
|
|
||||||
option_index = indfound;
|
|
||||||
if (*nameend)
|
|
||||||
{
|
|
||||||
if (pfound->has_arg)
|
|
||||||
d->optarg = nameend + 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr, _T("\
|
|
||||||
%s: option '-W %s' doesn't allow an argument\n"),
|
|
||||||
argv[0], pfound->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
return _T('?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (pfound->has_arg == 1)
|
|
||||||
{
|
|
||||||
if (d->optind < argc)
|
|
||||||
d->optarg = argv[d->optind++];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr, _T("\
|
|
||||||
%s: option '-W %s' requires an argument\n"),
|
|
||||||
argv[0], pfound->name);
|
|
||||||
}
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
return optstring[0] == _T(':') ? _T(':') : _T('?');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d->optarg = NULL;
|
|
||||||
d->__nextchar += _tcslen(d->__nextchar);
|
|
||||||
if (longind != NULL)
|
|
||||||
*longind = option_index;
|
|
||||||
if (pfound->flag)
|
|
||||||
{
|
|
||||||
*(pfound->flag) = pfound->val;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return pfound->val;
|
|
||||||
}
|
|
||||||
d->__nextchar = NULL;
|
|
||||||
return _T('W');
|
|
||||||
}
|
|
||||||
if (temp[1] == _T(':'))
|
|
||||||
{
|
|
||||||
if (temp[2] == _T(':'))
|
|
||||||
{
|
|
||||||
if (*d->__nextchar != _T('\0'))
|
|
||||||
{
|
|
||||||
d->optarg = d->__nextchar;
|
|
||||||
d->optind++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d->optarg = NULL;
|
|
||||||
d->__nextchar = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (*d->__nextchar != _T('\0'))
|
|
||||||
{
|
|
||||||
d->optarg = d->__nextchar;
|
|
||||||
d->optind++;
|
|
||||||
}
|
|
||||||
else if (d->optind == argc)
|
|
||||||
{
|
|
||||||
if (print_errors)
|
|
||||||
{
|
|
||||||
_ftprintf(stderr,
|
|
||||||
_T("%s: option requires an argument -- '%c'\n"),
|
|
||||||
argv[0], c);
|
|
||||||
}
|
|
||||||
d->optopt = c;
|
|
||||||
if (optstring[0] == _T(':'))
|
|
||||||
c = _T(':');
|
|
||||||
else
|
|
||||||
c = _T('?');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
d->optarg = argv[d->optind++];
|
|
||||||
d->__nextchar = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getopt_internal (int argc, TCHAR *const *argv, const TCHAR *optstring, const struct option *longopts, int *longind, int long_only, int posixly_correct)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
getopt_data.optind = optind;
|
|
||||||
getopt_data.opterr = opterr;
|
|
||||||
result = _getopt_internal_r (argc, argv, optstring, longopts,longind, long_only, &getopt_data,posixly_correct);
|
|
||||||
optind = getopt_data.optind;
|
|
||||||
optarg = getopt_data.optarg;
|
|
||||||
optopt = getopt_data.optopt;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getopt (int argc, TCHAR *const *argv, const TCHAR *optstring)
|
|
||||||
{
|
|
||||||
return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getopt_long (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index)
|
|
||||||
{
|
|
||||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getopt_long_r (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index, struct _getopt_data *d)
|
|
||||||
{
|
|
||||||
return _getopt_internal_r (argc, argv, options, long_options, opt_index,0, d, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getopt_long_only (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index)
|
|
||||||
{
|
|
||||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int _getopt_long_only_r (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index, struct _getopt_data *d)
|
|
||||||
{
|
|
||||||
return _getopt_internal_r (argc, argv, options, long_options, opt_index, 1, d, 0);
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/* Getopt for Microsoft C
|
|
||||||
This code is a modification of the Free Software Foundation, Inc.
|
|
||||||
Getopt library for parsing command line argument the purpose was
|
|
||||||
to provide a Microsoft Visual C friendly derivative. This code
|
|
||||||
provides functionality for both Unicode and Multibyte builds.
|
|
||||||
|
|
||||||
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
|
|
||||||
Version: 1.0
|
|
||||||
Comment: Supports getopt, getopt_long, and getopt_long_only
|
|
||||||
and POSIXLY_CORRECT environment flag
|
|
||||||
License: LGPL
|
|
||||||
|
|
||||||
Revisions:
|
|
||||||
|
|
||||||
02/03/2011 - Ludvik Jerabek - Initial Release
|
|
||||||
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
|
|
||||||
|
|
||||||
**DISCLAIMER**
|
|
||||||
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
|
|
||||||
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
|
|
||||||
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
|
|
||||||
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
|
|
||||||
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
|
|
||||||
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
|
|
||||||
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
|
|
||||||
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
*/
|
|
||||||
#ifndef __GETOPT_H_
|
|
||||||
#define __GETOPT_H_
|
|
||||||
|
|
||||||
#include <tchar.h>
|
|
||||||
|
|
||||||
#define ARG_NULL 0 /*Argument Null*/
|
|
||||||
#define ARG_NONE 0 /*Argument Switch Only*/
|
|
||||||
#define ARG_REQ 1 /*Argument Required*/
|
|
||||||
#define ARG_OPT 2 /*Argument Optional*/
|
|
||||||
|
|
||||||
// Change behavior for C\C++
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define _BEGIN_EXTERN_C extern "C" {
|
|
||||||
#define _END_EXTERN_C }
|
|
||||||
#define _GETOPT_THROW throw()
|
|
||||||
#else
|
|
||||||
#define _BEGIN_EXTERN_C
|
|
||||||
#define _END_EXTERN_C
|
|
||||||
#define _GETOPT_THROW
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_BEGIN_EXTERN_C
|
|
||||||
extern TCHAR *optarg;
|
|
||||||
extern int optind;
|
|
||||||
extern int opterr;
|
|
||||||
extern int optopt;
|
|
||||||
struct option
|
|
||||||
{
|
|
||||||
const TCHAR* name;
|
|
||||||
int has_arg;
|
|
||||||
int *flag;
|
|
||||||
TCHAR val;
|
|
||||||
};
|
|
||||||
extern int getopt(int argc, TCHAR *const *argv, const TCHAR *optstring) _GETOPT_THROW;
|
|
||||||
extern int getopt_long(int ___argc, TCHAR *const *___argv, const TCHAR *__shortopts, const struct option *__longopts, int *__longind) _GETOPT_THROW;
|
|
||||||
extern int getopt_long_only(int ___argc, TCHAR *const *___argv, const TCHAR *__shortopts, const struct option *__longopts, int *__longind) _GETOPT_THROW;
|
|
||||||
_END_EXTERN_C
|
|
||||||
|
|
||||||
// Undefine so the macros are not included
|
|
||||||
#undef _BEGIN_EXTERN_C
|
|
||||||
#undef _END_EXTERN_C
|
|
||||||
#undef _GETOPT_THROW
|
|
||||||
|
|
||||||
#endif // __GETOPT_H_
|
|
@ -1,111 +0,0 @@
|
|||||||
Index: rtmpdump.c
|
|
||||||
===================================================================
|
|
||||||
--- rtmpdump.c (revision 256)
|
|
||||||
+++ rtmpdump.c (working copy)
|
|
||||||
@@ -25,9 +25,11 @@
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
+#include <tchar.h>
|
|
||||||
+#include <stdarg.h>
|
|
||||||
|
|
||||||
#include <signal.h> // to catch Ctrl-C
|
|
||||||
-#include <getopt.h>
|
|
||||||
+#include "getopt.h"
|
|
||||||
|
|
||||||
#include "rtmp.h"
|
|
||||||
#include "log.h"
|
|
||||||
@@ -38,6 +40,7 @@
|
|
||||||
#define ftello ftello64
|
|
||||||
#include <io.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
+#include <windows.h>
|
|
||||||
#define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
|
|
||||||
#else
|
|
||||||
#define SET_BINMODE(f)
|
|
||||||
@@ -542,7 +545,7 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
-OpenResumeFile(const char *flvFile, // file name [in]
|
|
||||||
+OpenResumeFile(const wchar_t *flvFile, // file name [in]
|
|
||||||
FILE ** file, // opened file [out]
|
|
||||||
off_t * size, // size of the file [out]
|
|
||||||
char **metaHeader, // meta data read from the file [out]
|
|
||||||
@@ -555,7 +558,7 @@
|
|
||||||
*nMetaHeaderSize = 0;
|
|
||||||
*size = 0;
|
|
||||||
|
|
||||||
- *file = fopen(flvFile, "r+b");
|
|
||||||
+ *file = _wfopen(flvFile, L"r+b");
|
|
||||||
if (!*file)
|
|
||||||
return RD_SUCCESS; // RD_SUCCESS, because we go to fresh file mode instead of quiting
|
|
||||||
|
|
||||||
@@ -1164,7 +1167,7 @@
|
|
||||||
int
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
- extern char *optarg;
|
|
||||||
+ extern TCHAR *optarg;
|
|
||||||
|
|
||||||
int nStatus = RD_SUCCESS;
|
|
||||||
double percent = 0;
|
|
||||||
@@ -1222,7 +1225,7 @@
|
|
||||||
unsigned char hash[HASHLEN];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
- char *flvFile = 0;
|
|
||||||
+ wchar_t *flvFile = 0;
|
|
||||||
|
|
||||||
#undef OSS
|
|
||||||
#ifdef WIN32
|
|
||||||
@@ -1264,6 +1267,24 @@
|
|
||||||
|
|
||||||
/* sleep(30); */
|
|
||||||
|
|
||||||
+ // parsing filepath and converting to unicode
|
|
||||||
+ wchar_t *uflvFile = 0;
|
|
||||||
+ #ifdef WIN32
|
|
||||||
+ wchar_t *cmdstr;
|
|
||||||
+ wchar_t **wargv;
|
|
||||||
+ int i;
|
|
||||||
+ // print parameters, including Unicode.
|
|
||||||
+ cmdstr = GetCommandLineW();
|
|
||||||
+ wargv = CommandLineToArgvW(cmdstr, &argc);
|
|
||||||
+ for (i = 0; i < argc; i++) {
|
|
||||||
+ if (wcscmp(wargv[i], L"-o") == 0)
|
|
||||||
+ {
|
|
||||||
+ uflvFile = wargv[i + 1];
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ #endif
|
|
||||||
+
|
|
||||||
int opt;
|
|
||||||
struct option longopts[] = {
|
|
||||||
{"help", 0, NULL, 'h'},
|
|
||||||
@@ -1535,10 +1556,12 @@
|
|
||||||
STR2AVAL(flashVer, optarg);
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
- flvFile = optarg;
|
|
||||||
- if (strcmp(flvFile, "-"))
|
|
||||||
+ flvFile = (wchar_t*)optarg;
|
|
||||||
+ if (wcscmp(flvFile, L"-"))
|
|
||||||
bStdoutMode = false;
|
|
||||||
-
|
|
||||||
+#ifdef WIN32
|
|
||||||
+ flvFile = uflvFile;
|
|
||||||
+#endif
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
bResume = true;
|
|
||||||
@@ -1749,7 +1772,7 @@
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
- file = fopen(flvFile, "w+b");
|
|
||||||
+ file = _wfopen(flvFile, L"w+b");
|
|
||||||
if (file == 0)
|
|
||||||
{
|
|
||||||
LogPrintf("Failed to open file! %s\n", flvFile);
|
|
Loading…
Reference in New Issue
Block a user