Merge branch 'devel' into v0.9
This commit is contained in:
commit
0a068311b1
27
.travis.yml
27
.travis.yml
@ -9,6 +9,12 @@ addons:
|
||||
packages: &common_deps
|
||||
- nasm
|
||||
|
||||
# This is required to use a version of cppcheck other than that
|
||||
# suplied with the operating system
|
||||
cppcheck_defs: &cppcheck_defs
|
||||
- CPPCHECK_VER=1.90
|
||||
- CPPCHECK_REPO=https://github.com/danmar/cppcheck.git
|
||||
|
||||
min_amd64_deps: &min_amd64_deps
|
||||
- *common_deps
|
||||
- libpam0g-dev
|
||||
@ -81,6 +87,22 @@ max_x86_conf: &max_x86_conf
|
||||
packages:
|
||||
- *max_x86_deps
|
||||
|
||||
# For cppcheck, we've got a custom script
|
||||
cppcheck_conf: &cppcheck_conf
|
||||
env:
|
||||
- *cppcheck_defs
|
||||
|
||||
# addons:
|
||||
# apt:
|
||||
# packages:
|
||||
# - cppcheck
|
||||
|
||||
script:
|
||||
- ./bootstrap
|
||||
- scripts/install_cppcheck.sh $CPPCHECK_REPO $CPPCHECK_VER
|
||||
- scripts/run_cppcheck.sh -v $CPPCHECK_VER
|
||||
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
||||
@ -108,6 +130,11 @@ matrix:
|
||||
- compiler: clang
|
||||
<< : *max_x86_conf
|
||||
|
||||
# cppcheck
|
||||
- name: cppcheck
|
||||
compiler: gcc
|
||||
<< : *cppcheck_conf
|
||||
|
||||
script:
|
||||
- ./bootstrap
|
||||
- ./configure $CONF_FLAGS
|
||||
|
27
NEWS.md
27
NEWS.md
@ -1,3 +1,30 @@
|
||||
# Release notes for xrdp v0.9.13 (2020/03/11)
|
||||
|
||||
This release is an intermediate bugfix release. The previous version v0.9.12 has some regressions on drive redirection.
|
||||
|
||||
## Bug fixes (drive redirection related)
|
||||
* Fix chansrv crashes with segmentation fault (regression in #1449) #1487
|
||||
* Drive redirection now supports Guacamole client #1505 #1507
|
||||
* Prevent a coredump in the event of a corrupted file system #1507
|
||||
* Resolve double-free in `chansrv_fuse` #1469
|
||||
|
||||
## Bug fixes (other)
|
||||
* Fix the issue `xrdp --version | less` will show empty output #1471 #1472
|
||||
* Fix some warnings found by cppcheck #1479 #1481 #1484 #1485
|
||||
|
||||
## Other changes
|
||||
* Add FreeBSD CI test #1466
|
||||
* Move Microsoft-defined constants into separate includes #1470
|
||||
* Perform cppcheck during CI test #1493
|
||||
* Support mousex button 8/9 #1478
|
||||
|
||||
## Known issues
|
||||
* FreeRDP 2.0.0-rc4 or later might not able to connect to xrdp due to
|
||||
xrdp's bad-mannered behaviour, add `+glyph-cache` option to FreeRDP to connect #1266
|
||||
* Audio redirection by MP3 codec doesn't sound with some client, use AAC instead #965
|
||||
|
||||
-----------------------
|
||||
|
||||
# Release notes for xrdp v0.9.12 (2019/12/28)
|
||||
|
||||
## Bug fixes
|
||||
|
@ -1,8 +1,8 @@
|
||||
[![Build Status](https://travis-ci.org/neutrinolabs/xrdp.svg?branch=devel)](https://travis-ci.org/neutrinolabs/xrdp)
|
||||
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp)
|
||||
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/neutrinolabs/xrdp-questions)
|
||||
![Apache-License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)
|
||||
|
||||
*Current Version:* 0.9.12
|
||||
*Current Version:* 0.9.13
|
||||
|
||||
# xrdp - an open source RDP server
|
||||
|
||||
|
@ -36,7 +36,8 @@ enum NTSTATUS
|
||||
STATUS_ACCESS_DENIED = 0xc0000022,
|
||||
STATUS_OBJECT_NAME_INVALID = 0xc0000033,
|
||||
STATUS_OBJECT_NAME_NOT_FOUND = 0xc0000034,
|
||||
STATUS_SHARING_VIOLATION = 0xc0000043
|
||||
STATUS_SHARING_VIOLATION = 0xc0000043,
|
||||
STATUS_NOT_SUPPORTED = 0xc00000bb
|
||||
};
|
||||
|
||||
#endif /* MS_ERREF_H */
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Process this file with autoconf to produce a configure script
|
||||
|
||||
AC_PREREQ(2.65)
|
||||
AC_INIT([xrdp], [0.9.12], [xrdp-devel@googlegroups.com])
|
||||
AC_INIT([xrdp], [0.9.13], [xrdp-devel@googlegroups.com])
|
||||
AC_CONFIG_HEADERS(config_ac.h:config_ac-h.in)
|
||||
AM_INIT_AUTOMAKE([1.7.2 foreign])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
105
scripts/install_cppcheck.sh
Executable file
105
scripts/install_cppcheck.sh
Executable file
@ -0,0 +1,105 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Script to install a version of cppcheck in ~/cppcheck.local/
|
||||
#
|
||||
# Used by Travis-CI builds, until Travis supports cppcheck natively
|
||||
#
|
||||
# Currently only supports git repos as sources
|
||||
#
|
||||
# Usage: /path/to/install_cppcheck.sh <cppcheck-git-repo> <version-tag>
|
||||
|
||||
INSTALL_ROOT=~/cppcheck.local
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# U S A G E
|
||||
# ----------------------------------------------------------------------------
|
||||
usage()
|
||||
{
|
||||
echo "** Usage: $0 <git-repo URL> <version-tag>"
|
||||
echo " e.g. $0 https://github.com/danmar/cppcheck.git 1.90"
|
||||
} >&2
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# C A L L _ M A K E
|
||||
#
|
||||
# Calls make with the specified parameters, but only displays the error
|
||||
# log if it fails
|
||||
# ----------------------------------------------------------------------------
|
||||
call_make()
|
||||
{
|
||||
# Disable set -e, if active
|
||||
set_entry_opts=`set +o`
|
||||
set +e
|
||||
|
||||
status=1
|
||||
log=`mktemp /tmp/cppcheck-log.XXXXXXXXXX`
|
||||
if [ -n "$log" ]; then
|
||||
make "$@" >$log 2>&1
|
||||
status=$?
|
||||
if [ $status -ne 0 ]; then
|
||||
cat $log >&2
|
||||
fi
|
||||
rm $log
|
||||
fi
|
||||
|
||||
# Re-enable `set -e` if active before
|
||||
$set_entry_opts
|
||||
|
||||
return $status
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# M A I N
|
||||
# ----------------------------------------------------------------------------
|
||||
if [ $# -ne 2 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
REPO_URL="$1"
|
||||
CPPCHECK_VER="$2"
|
||||
|
||||
# Already installed?
|
||||
exe=$INSTALL_ROOT/$CPPCHECK_VER/bin/cppcheck
|
||||
if [ -x "$exe" ]; then
|
||||
echo "cppcheck version $CPPCHECK_VER is already installed at $exe" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
workdir=`mktemp -d /tmp/cppcheck.XXXXXXXXXX`
|
||||
if [ -z "$workdir" ]; then
|
||||
echo "** Unable to create temporary working directory" 2>&1
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use a sub-process for the next bit to restrict the scope of 'set -e'
|
||||
(
|
||||
set -e ; # Exit sub-process on first error
|
||||
|
||||
# Put everything in this directory
|
||||
FILESDIR=$INSTALL_ROOT/$CPPCHECK_VER
|
||||
|
||||
# CFGDIR is needed for cppcheck before 1.86
|
||||
make_args="FILESDIR=$FILESDIR PREFIX=$FILESDIR CFGDIR=$FILESDIR"
|
||||
|
||||
# See https://stackoverflow.com/questions/
|
||||
# 791959/download-a-specific-tag-with-git
|
||||
git clone -b $CPPCHECK_VER --depth 1 $REPO_URL $workdir
|
||||
|
||||
cd $workdir
|
||||
echo "Making cppcheck..."
|
||||
# CFGDIR is needed for cppcheck before 1.86
|
||||
call_make $make_args
|
||||
|
||||
echo "Installing cppcheck..."
|
||||
mkdir -p $FILESDIR
|
||||
call_make install $make_args
|
||||
)
|
||||
status=$?
|
||||
|
||||
if [ $status -eq 0 ]; then
|
||||
rm -rf $workdir
|
||||
else
|
||||
"** Script failed. Work dir is $workdir" >&2
|
||||
fi
|
||||
|
||||
exit $status
|
58
scripts/run_cppcheck.sh
Executable file
58
scripts/run_cppcheck.sh
Executable file
@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Script to run cppcheck
|
||||
#
|
||||
# Usage: /path/to/run_cppcheck.sh [ -v CPPCHECK_VER] [<extra_opts_and_dirs>]
|
||||
#
|
||||
# - If <extra_opts_and_dirs> is missing, '.' is assumed
|
||||
# - If -v CPPCHECK_VER is specified, that version of cppcheck is run from
|
||||
# ~/cppcheck.local (whether or not it's there!). Use install_cppcheck.sh
|
||||
# to install a new version.
|
||||
#
|
||||
# Environment (all optional):-
|
||||
#
|
||||
# CPPCHECK : Override the default cppcheck command ('cppcheck').
|
||||
# Ignored if -v is specified
|
||||
# CPPCHECK_FLAGS : Override the default cppcheck flags
|
||||
|
||||
INSTALL_ROOT=~/cppcheck.local
|
||||
|
||||
# Figure out CPPCHECK setting, if any. Currently '-v' must be the first
|
||||
# argument on the command line.
|
||||
case "$1" in
|
||||
-v) # Version is separate parameter
|
||||
if [ $# -ge 2 ]; then
|
||||
CPPCHECK="$INSTALL_ROOT/$2/bin/cppcheck"
|
||||
shift 2
|
||||
else
|
||||
echo "** ignoring '-v' with no arg" >&2
|
||||
shift 1
|
||||
fi
|
||||
;;
|
||||
-v*) # Version is in same parameter
|
||||
# ${parameter#word} is not supported by classic Bourne shell,
|
||||
# but it is on bash, dash, etc. If it doesn't work on your shell,
|
||||
# don't use this form!
|
||||
CPPCHECK="$INSTALL_ROOT/${1#-v}/bin/cppcheck"
|
||||
shift 1
|
||||
esac
|
||||
if [ -z "$CPPCHECK" ]; then
|
||||
CPPCHECK=cppcheck
|
||||
fi
|
||||
|
||||
# Supply default flags passed to cppcheck if necessary
|
||||
if [ -z "$CPPCHECK_FLAGS" ]; then
|
||||
CPPCHECK_FLAGS="--quiet --force --std=c11 --std=c++11 --inline-suppr \
|
||||
--enable=warning --error-exitcode=1"
|
||||
fi
|
||||
|
||||
# Any options/directories specified?
|
||||
if [ $# -eq 0 ]; then
|
||||
set -- .
|
||||
fi
|
||||
|
||||
# Display the cppcheck version and command for debugging
|
||||
"$CPPCHECK" --version && {
|
||||
echo Command: $CPPCHECK $CPPCHECK_FLAGS "$@"
|
||||
"$CPPCHECK" $CPPCHECK_FLAGS "$@"
|
||||
}
|
@ -78,6 +78,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
|
||||
tui32 DeviceId, tui32 FileId)
|
||||
{}
|
||||
void xfuse_devredir_cb_read_file(struct state_read *fip,
|
||||
enum NTSTATUS IoStatus,
|
||||
const char *buf, size_t length)
|
||||
{}
|
||||
void xfuse_devredir_cb_write_file(
|
||||
@ -637,6 +638,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname)
|
||||
}
|
||||
else
|
||||
{
|
||||
xinode->is_redirected = 1;
|
||||
xinode->device_id = device_id;
|
||||
result = 0;
|
||||
}
|
||||
@ -653,7 +655,7 @@ int xfuse_create_share(tui32 device_id, const char *dirname)
|
||||
|
||||
void xfuse_delete_share(tui32 device_id)
|
||||
{
|
||||
xfs_delete_entries_with_device_id(g_xfs, device_id);
|
||||
xfs_delete_redirected_entries_with_device_id(g_xfs, device_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1313,9 +1315,18 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
|
||||
}
|
||||
|
||||
void xfuse_devredir_cb_read_file(struct state_read *fip,
|
||||
enum NTSTATUS IoStatus,
|
||||
const char *buf, size_t length)
|
||||
{
|
||||
fuse_reply_buf(fip->req, buf, length);
|
||||
if (IoStatus != STATUS_SUCCESS)
|
||||
{
|
||||
log_error("Read NTSTATUS is %d", (int) IoStatus);
|
||||
fuse_reply_err(fip->req, EIO);
|
||||
}
|
||||
else
|
||||
{
|
||||
fuse_reply_buf(fip->req, buf, length);
|
||||
}
|
||||
free(fip);
|
||||
}
|
||||
|
||||
@ -1438,7 +1449,7 @@ static void xfuse_cb_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parent_xinode->device_id == 0)
|
||||
if (!parent_xinode->is_redirected)
|
||||
{
|
||||
/* File cannot be remote - we either know about it or we don't */
|
||||
if ((xinode = xfs_lookup_in_dir(g_xfs, parent, name)) != NULL)
|
||||
@ -1673,13 +1684,13 @@ static void xfuse_cb_unlink(fuse_req_t req, fuse_ino_t parent,
|
||||
fuse_reply_err(req, ENOTEMPTY);
|
||||
}
|
||||
|
||||
else if (xinode->device_id == 0)
|
||||
else if (!xinode->is_redirected)
|
||||
{
|
||||
/* specified file is a local resource */
|
||||
//XFUSE_HANDLE *fh;
|
||||
|
||||
log_debug("LK_TODO: this is still a TODO");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
fuse_reply_err(req, EROFS);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1744,26 +1755,27 @@ static void xfuse_cb_rename(fuse_req_t req,
|
||||
else if (!(new_parent_xinode = xfs_get(g_xfs, new_parent)))
|
||||
{
|
||||
log_error("inode %ld is not valid", new_parent);
|
||||
fuse_reply_err(req, EINVAL);
|
||||
fuse_reply_err(req, ENOENT);
|
||||
}
|
||||
|
||||
else if (!xfs_check_move_entry(g_xfs, old_xinode->inum,
|
||||
new_parent, new_name))
|
||||
{
|
||||
/* Catchall -see rename(2). Fix when logging is improved */
|
||||
fuse_reply_err(req, EINVAL);
|
||||
}
|
||||
|
||||
else if (new_parent_xinode->device_id != old_xinode->device_id)
|
||||
else if (new_parent_xinode->is_redirected != old_xinode->is_redirected ||
|
||||
new_parent_xinode->device_id != old_xinode->device_id)
|
||||
{
|
||||
log_error("rename across file systems not supported");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
fuse_reply_err(req, EXDEV);
|
||||
}
|
||||
|
||||
else if (old_xinode->device_id == 0)
|
||||
else if (!old_xinode->is_redirected)
|
||||
{
|
||||
/* specified file is a local resource */
|
||||
log_debug("LK_TODO: this is still a TODO");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
fuse_reply_err(req, EROFS);
|
||||
}
|
||||
|
||||
else
|
||||
@ -1853,20 +1865,25 @@ static void xfuse_create_dir_or_file(fuse_req_t req, fuse_ino_t parent,
|
||||
}
|
||||
|
||||
/* is parent inode valid? */
|
||||
if (parent == FUSE_ROOT_ID ||
|
||||
(xinode = xfs_get(g_xfs, parent)) == NULL ||
|
||||
(xinode->mode & S_IFDIR) == 0)
|
||||
if (parent == FUSE_ROOT_ID)
|
||||
{
|
||||
fuse_reply_err(req, EROFS);
|
||||
}
|
||||
else if ((xinode = xfs_get(g_xfs, parent)) == NULL)
|
||||
{
|
||||
log_error("inode %ld is not valid", parent);
|
||||
fuse_reply_err(req, ENOENT);
|
||||
}
|
||||
else if (xinode->device_id == 0)
|
||||
else if ((xinode->mode & S_IFDIR) == 0)
|
||||
{
|
||||
fuse_reply_err(req, ENOTDIR);
|
||||
}
|
||||
else if (!xinode->is_redirected)
|
||||
{
|
||||
/* specified file is a local resource */
|
||||
//XFUSE_HANDLE *fh;
|
||||
|
||||
log_debug("LK_TODO: this is still a TODO");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
fuse_reply_err(req, EROFS);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1945,13 +1962,20 @@ static void xfuse_cb_open(fuse_req_t req, fuse_ino_t ino,
|
||||
log_debug("Invalid access mode specified");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
}
|
||||
else if (xinode->device_id == 0)
|
||||
else if (!xinode->is_redirected)
|
||||
{
|
||||
/* specified file is a local resource */
|
||||
XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1);
|
||||
fh->is_loc_resource = 1;
|
||||
fi->fh = (tintptr) fh;
|
||||
fuse_reply_open(req, fi);
|
||||
if ((fi->flags & O_ACCMODE) != O_RDONLY)
|
||||
{
|
||||
fuse_reply_err(req, EROFS);
|
||||
}
|
||||
else
|
||||
{
|
||||
XFUSE_HANDLE *fh = g_new0(XFUSE_HANDLE, 1);
|
||||
fh->is_loc_resource = 1;
|
||||
fi->fh = (tintptr) fh;
|
||||
fuse_reply_open(req, fi);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2017,7 +2041,7 @@ static void xfuse_cb_release(fuse_req_t req, fuse_ino_t ino, struct
|
||||
log_error("inode %ld is not valid", ino);
|
||||
fuse_reply_err(req, ENOENT);
|
||||
}
|
||||
else if (xinode->device_id == 0)
|
||||
else if (!xinode->is_redirected)
|
||||
{
|
||||
/* specified file is a local resource */
|
||||
fuse_reply_err(req, 0);
|
||||
@ -2153,7 +2177,7 @@ static void xfuse_cb_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
|
||||
{
|
||||
/* target file is in .clipboard dir */
|
||||
log_debug("THIS IS STILL A TODO!");
|
||||
fuse_reply_err(req, EINVAL);
|
||||
fuse_reply_err(req, EROFS);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2283,7 +2307,7 @@ static void xfuse_cb_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
|
||||
/* No changes have been made */
|
||||
make_fuse_attr_reply(req, xinode);
|
||||
}
|
||||
else if (xinode->device_id == 0)
|
||||
else if (!xinode->is_redirected)
|
||||
{
|
||||
/* Update the local fs */
|
||||
update_inode_file_attributes(&attrs, change_mask, xinode);
|
||||
@ -2349,7 +2373,7 @@ static void xfuse_cb_opendir(fuse_req_t req, fuse_ino_t ino,
|
||||
log_error("inode %ld is not valid", ino);
|
||||
fuse_reply_err(req, ENOENT);
|
||||
}
|
||||
else if (xinode->device_id == 0)
|
||||
else if (!xinode->is_redirected)
|
||||
{
|
||||
if ((fi->fh = (tintptr) xfs_opendir(g_xfs, ino)) == 0)
|
||||
{
|
||||
@ -2537,6 +2561,8 @@ static char *get_name_for_entry_in_parent(fuse_ino_t parent, const char *name)
|
||||
strlen(result) + 1 + strlen(name) + 1);
|
||||
if (p == NULL)
|
||||
{
|
||||
/* See cppcheck trac #9292 and #9437 */
|
||||
/* cppcheck-suppress doubleFree symbolName=result */
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
@ -98,6 +98,7 @@ void xfuse_devredir_cb_open_file(struct state_open *fip,
|
||||
tui32 DeviceId, tui32 FileId);
|
||||
|
||||
void xfuse_devredir_cb_read_file(struct state_read *fip,
|
||||
enum NTSTATUS IoStatus,
|
||||
const char *buf, size_t length);
|
||||
void xfuse_devredir_cb_write_file(
|
||||
struct state_write *fip,
|
||||
|
@ -344,6 +344,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
||||
xino1->pub.ctime = xino1->pub.atime;
|
||||
strcpy(xino1->pub.name, ".");
|
||||
xino1->pub.generation = xfs->generation;
|
||||
xino1->pub.is_redirected = 0;
|
||||
xino1->pub.device_id = 0;
|
||||
|
||||
/*
|
||||
@ -365,6 +366,7 @@ xfs_create_xfs_fs(mode_t umask, uid_t uid, gid_t gid)
|
||||
xino2->pub.ctime = xino2->pub.atime;
|
||||
strcpy(xino2->pub.name, ".delete-pending");
|
||||
xino2->pub.generation = xfs->generation;
|
||||
xino2->pub.is_redirected = 0;
|
||||
xino2->pub.device_id = 0;
|
||||
|
||||
xino2->parent = NULL;
|
||||
@ -469,6 +471,7 @@ xfs_add_entry(struct xfs_fs *xfs, fuse_ino_t parent_inum,
|
||||
xino->pub.ctime = xino->pub.atime;
|
||||
strcpy(xino->pub.name, name);
|
||||
xino->pub.generation = xfs->generation;
|
||||
xino->pub.is_redirected = parent->pub.is_redirected;
|
||||
xino->pub.device_id = parent->pub.device_id;
|
||||
xino->pub.lindex = 0;
|
||||
|
||||
@ -565,7 +568,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||
*/
|
||||
size_t len = 0;
|
||||
XFS_INODE_ALL *p;
|
||||
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
|
||||
for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
|
||||
{
|
||||
len += strlen(p->pub.name);
|
||||
++len; /* Allow for '/' prefix */
|
||||
@ -578,7 +581,7 @@ xfs_get_full_path(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||
char *end = result + len;
|
||||
*end = '\0';
|
||||
|
||||
for (p = xino ; p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
|
||||
for (p = xino ; p && p->pub.inum != FUSE_ROOT_ID ; p = p->parent)
|
||||
{
|
||||
len = strlen(p->pub.name);
|
||||
end -= (len + 1);
|
||||
@ -816,35 +819,35 @@ xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum)
|
||||
|
||||
/* ------------------------------------------------------------------------ */
|
||||
void
|
||||
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id)
|
||||
xfs_delete_redirected_entries_with_device_id(struct xfs_fs *xfs,
|
||||
tui32 device_id)
|
||||
{
|
||||
fuse_ino_t inum;
|
||||
XFS_INODE_ALL *xino;
|
||||
|
||||
if (device_id != 0)
|
||||
/* Using xfs_remove_entry() is convenient, but it recurses
|
||||
* in to directories. To make sure all entries are removed, set the
|
||||
* open_count of all affected files to 0 first
|
||||
*/
|
||||
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
|
||||
{
|
||||
/* Using xfs_remove_entry() is convenient, but it recurses
|
||||
* in to directories. To make sure all entries are removed, set the
|
||||
* open_count of all affected files to 0 first
|
||||
*/
|
||||
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
|
||||
if ((xino = xfs->inode_table[inum]) != NULL &&
|
||||
xino->pub.is_redirected != 0 &&
|
||||
xino->pub.device_id == device_id &&
|
||||
(xino->pub.mode & S_IFREG) != 0)
|
||||
{
|
||||
if ((xino = xfs->inode_table[inum]) != NULL &&
|
||||
xino->pub.device_id == device_id &&
|
||||
(xino->pub.mode & S_IFREG) != 0)
|
||||
{
|
||||
xino->open_count = 0;
|
||||
}
|
||||
xino->open_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we can be sure everything will be deleted correctly */
|
||||
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
|
||||
/* Now we can be sure everything will be deleted correctly */
|
||||
for (inum = FUSE_ROOT_ID; inum < xfs->inode_count; ++inum)
|
||||
{
|
||||
if ((xino = xfs->inode_table[inum]) != NULL &&
|
||||
xino->pub.is_redirected != 0 &&
|
||||
xino->pub.device_id == device_id)
|
||||
{
|
||||
if ((xino = xfs->inode_table[inum]) != NULL &&
|
||||
xino->pub.device_id == device_id)
|
||||
{
|
||||
xfs_remove_entry(xfs, xino->pub.inum);
|
||||
}
|
||||
xfs_remove_entry(xfs, xino->pub.inum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,8 @@ typedef struct xfs_inode
|
||||
time_t ctime; /* Time of last status change. */
|
||||
char name[XFS_MAXFILENAMELEN + 1]; /* Short name */
|
||||
tui32 generation; /* Changes if inode is reused */
|
||||
tui32 device_id; /* for file system redirection
|
||||
* Non-redirected devices are guaranteed
|
||||
* to have a device_id or zero */
|
||||
char is_redirected; /* file is on redirected device */
|
||||
tui32 device_id; /* device ID of redirected device */
|
||||
int lindex; /* used in clipboard operations */
|
||||
} XFS_INODE;
|
||||
|
||||
@ -271,17 +270,15 @@ unsigned int
|
||||
xfs_get_file_open_count(struct xfs_fs *xfs, fuse_ino_t inum);
|
||||
|
||||
/*
|
||||
* Deletes all entries with the matching device id
|
||||
* Deletes all redirected entries with the matching device id
|
||||
*
|
||||
* Files are deleted even if they are open
|
||||
*
|
||||
* The specified device_id must be non-zero so that the root
|
||||
* filesystem is not deleted!
|
||||
*
|
||||
* @param device_id Device ID
|
||||
*/
|
||||
void
|
||||
xfs_delete_entries_with_device_id(struct xfs_fs *xfs, tui32 device_id);
|
||||
xfs_delete_redirected_entries_with_device_id(struct xfs_fs *xfs,
|
||||
tui32 device_id);
|
||||
|
||||
/*
|
||||
* Check an entry move will be successful
|
||||
|
@ -185,28 +185,10 @@ devredir_init(void)
|
||||
{
|
||||
struct stream *s;
|
||||
int bytes;
|
||||
int fd;
|
||||
|
||||
union _u
|
||||
{
|
||||
tui32 clientID;
|
||||
char buf[4];
|
||||
} u;
|
||||
tui32 clientID;
|
||||
|
||||
/* get a random number that will act as a unique clientID */
|
||||
if ((fd = open("/dev/urandom", O_RDONLY)) != -1)
|
||||
{
|
||||
if (read(fd, u.buf, 4) != 4)
|
||||
{
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* /dev/urandom did not work - use address of struct s */
|
||||
tui64 u64 = (tui64) (tintptr) &s;
|
||||
u.clientID = (tui32) u64;
|
||||
}
|
||||
g_random((char *) &clientID, sizeof(clientID));
|
||||
|
||||
/* setup stream */
|
||||
xstream_new(s, 1024);
|
||||
@ -216,7 +198,7 @@ devredir_init(void)
|
||||
xstream_wr_u16_le(s, PAKID_CORE_SERVER_ANNOUNCE);
|
||||
xstream_wr_u16_le(s, 0x0001); /* server major ver */
|
||||
xstream_wr_u16_le(s, 0x000C); /* server minor ver - pretend 2 b Win 7 */
|
||||
xstream_wr_u32_le(s, u.clientID); /* unique ClientID */
|
||||
xstream_wr_u32_le(s, clientID); /* unique ClientID */
|
||||
|
||||
/* send data to client */
|
||||
bytes = xstream_len(s);
|
||||
@ -578,7 +560,8 @@ devredir_send_server_user_logged_on(void)
|
||||
}
|
||||
|
||||
static void
|
||||
devredir_send_server_device_announce_resp(tui32 device_id)
|
||||
devredir_send_server_device_announce_resp(tui32 device_id,
|
||||
enum NTSTATUS result_code)
|
||||
{
|
||||
struct stream *s;
|
||||
int bytes;
|
||||
@ -589,7 +572,7 @@ devredir_send_server_device_announce_resp(tui32 device_id)
|
||||
xstream_wr_u16_le(s, RDPDR_CTYP_CORE);
|
||||
xstream_wr_u16_le(s, PAKID_CORE_DEVICE_REPLY);
|
||||
xstream_wr_u32_le(s, device_id);
|
||||
xstream_wr_u32_le(s, 0); /* ResultCode */
|
||||
xstream_wr_u32_le(s, (tui32)result_code);
|
||||
|
||||
/* send to client */
|
||||
bytes = xstream_len(s);
|
||||
@ -829,6 +812,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
|
||||
tui32 device_type;
|
||||
tui32 device_data_len;
|
||||
char preferred_dos_name[9];
|
||||
enum NTSTATUS response_status;
|
||||
|
||||
/* get number of devices being announced */
|
||||
xstream_rd_u32_le(s, device_count);
|
||||
@ -839,19 +823,20 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
|
||||
{
|
||||
xstream_rd_u32_le(s, device_type);
|
||||
xstream_rd_u32_le(s, g_device_id);
|
||||
/* get preferred DOS name
|
||||
* DOS names that are 8 chars long are not NULL terminated */
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
preferred_dos_name[j] = *s->p++;
|
||||
}
|
||||
preferred_dos_name[8] = 0;
|
||||
|
||||
/* Assume this device isn't supported by us */
|
||||
response_status = STATUS_NOT_SUPPORTED;
|
||||
|
||||
switch (device_type)
|
||||
{
|
||||
case RDPDR_DTYP_FILESYSTEM:
|
||||
/* get preferred DOS name */
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
preferred_dos_name[j] = *s->p++;
|
||||
}
|
||||
|
||||
/* DOS names that are 8 chars long are not NULL terminated */
|
||||
preferred_dos_name[8] = 0;
|
||||
|
||||
/* get device data len */
|
||||
xstream_rd_u32_le(s, device_data_len);
|
||||
if (device_data_len)
|
||||
@ -865,7 +850,7 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
|
||||
preferred_dos_name,
|
||||
device_data_len, g_full_name_for_filesystem);
|
||||
|
||||
devredir_send_server_device_announce_resp(g_device_id);
|
||||
response_status = STATUS_SUCCESS;
|
||||
|
||||
/* create share directory in xrdp file system; */
|
||||
/* think of this as the mount point for this share */
|
||||
@ -873,31 +858,44 @@ devredir_proc_client_devlist_announce_req(struct stream *s)
|
||||
break;
|
||||
|
||||
case RDPDR_DTYP_SMARTCARD:
|
||||
/* get preferred DOS name */
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
preferred_dos_name[j] = *s->p++;
|
||||
}
|
||||
|
||||
/* DOS names that are 8 chars long are not NULL terminated */
|
||||
preferred_dos_name[8] = 0;
|
||||
|
||||
/* for smart cards, device data len always 0 */
|
||||
|
||||
log_debug("device_type=SMARTCARD device_id=0x%x dosname=%s",
|
||||
g_device_id, preferred_dos_name);
|
||||
|
||||
devredir_send_server_device_announce_resp(g_device_id);
|
||||
response_status = STATUS_SUCCESS;
|
||||
|
||||
scard_device_announce(g_device_id);
|
||||
break;
|
||||
|
||||
/* we don't yet support these devices */
|
||||
case RDPDR_DTYP_SERIAL:
|
||||
log_debug(
|
||||
"device_type=SERIAL device_id=0x%x dosname=%s",
|
||||
g_device_id, preferred_dos_name);
|
||||
break;
|
||||
|
||||
case RDPDR_DTYP_PARALLEL:
|
||||
log_debug(
|
||||
"device_type=PARALLEL device_id=0x%x dosname=%s",
|
||||
g_device_id, preferred_dos_name);
|
||||
break;
|
||||
|
||||
case RDPDR_DTYP_PRINT:
|
||||
log_debug("unsupported dev: 0x%x", device_type);
|
||||
log_debug(
|
||||
"device_type=PRINT device_id=0x%x dosname=%s",
|
||||
g_device_id, preferred_dos_name);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_debug(
|
||||
"device_type=UNKNOWN device_id=0x%x dosname=%s",
|
||||
g_device_id, preferred_dos_name);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Tell the client wheth or not we're supporting this one */
|
||||
devredir_send_server_device_announce_resp(g_device_id,
|
||||
response_status);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1011,6 +1009,7 @@ devredir_proc_device_iocompletion(struct stream *s)
|
||||
case CID_READ:
|
||||
xstream_rd_u32_le(s, Length);
|
||||
xfuse_devredir_cb_read_file((struct state_read *) irp->fuse_info,
|
||||
IoStatus,
|
||||
s->p, Length);
|
||||
devredir_irp_delete(irp);
|
||||
break;
|
||||
@ -1529,10 +1528,10 @@ devredir_rmdir_or_file(struct state_remove *fusep, tui32 device_id,
|
||||
/**
|
||||
* Read data from previously opened file
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
* Errors are reported via xfuse_devredir_cb_read_file()
|
||||
*****************************************************************************/
|
||||
|
||||
int
|
||||
void
|
||||
devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
|
||||
tui32 Length, tui64 Offset)
|
||||
{
|
||||
@ -1540,7 +1539,6 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
|
||||
IRP *irp;
|
||||
IRP *new_irp;
|
||||
int bytes;
|
||||
int rval = -1;
|
||||
|
||||
xstream_new(s, 1024);
|
||||
|
||||
@ -1548,14 +1546,14 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
|
||||
if ((irp = devredir_irp_find_by_fileid(FileId)) == NULL)
|
||||
{
|
||||
log_error("no IRP found with FileId = %d", FileId);
|
||||
xfuse_devredir_cb_read_file(fusep, NULL, 0);
|
||||
xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0);
|
||||
xstream_free(s);
|
||||
}
|
||||
/* create a new IRP for this request */
|
||||
else if ((new_irp = devredir_irp_new()) == NULL)
|
||||
{
|
||||
/* system out of memory */
|
||||
xfuse_devredir_cb_read_file(fusep, NULL, 0);
|
||||
xfuse_devredir_cb_read_file(fusep, STATUS_UNSUCCESSFUL, NULL, 0);
|
||||
xstream_free(s);
|
||||
}
|
||||
else
|
||||
@ -1581,13 +1579,16 @@ devredir_file_read(struct state_read *fusep, tui32 DeviceId, tui32 FileId,
|
||||
bytes = xstream_len(s);
|
||||
send_channel_data(g_rdpdr_chan_id, s->data, bytes);
|
||||
xstream_free(s);
|
||||
rval = 0;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
/**
|
||||
* Read data from previously opened file
|
||||
*
|
||||
* Errors are reported via xfuse_devredir_cb_write_file()
|
||||
*****************************************************************************/
|
||||
|
||||
void
|
||||
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
|
||||
const char *buf, int Length, tui64 Offset)
|
||||
{
|
||||
@ -1595,7 +1596,6 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
|
||||
IRP *irp;
|
||||
IRP *new_irp;
|
||||
int bytes;
|
||||
int rval = -1;
|
||||
|
||||
log_debug("DeviceId=%d FileId=%d Length=%d Offset=%lld",
|
||||
DeviceId, FileId, Length, (long long)Offset);
|
||||
@ -1643,10 +1643,7 @@ devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
|
||||
bytes = xstream_len(s);
|
||||
send_channel_data(g_rdpdr_chan_id, s->data, bytes);
|
||||
xstream_free(s);
|
||||
rval = 0;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,12 +78,13 @@ int devredir_file_open(struct state_open *fusep, tui32 device_id,
|
||||
int devredir_file_close(struct state_close *fusep, tui32 device_id,
|
||||
tui32 file_id);
|
||||
|
||||
int devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
|
||||
tui32 Length, tui64 Offset);
|
||||
void
|
||||
devredir_file_read(struct state_read *fusep, tui32 device_id, tui32 FileId,
|
||||
tui32 Length, tui64 Offset);
|
||||
|
||||
int
|
||||
void
|
||||
devredir_file_write(struct state_write *fusep, tui32 DeviceId, tui32 FileId,
|
||||
const char *buf, int Length, tui64 Offset);
|
||||
const char *buf, int Length, tui64 Offset);
|
||||
|
||||
int devredir_file_rename(
|
||||
struct state_rename *fusep, tui32 device_id,
|
||||
|
@ -37,8 +37,6 @@ int g_rem_io_count = 0; // bytes read from remote port
|
||||
static int g_terminated = 0;
|
||||
static char g_buf[1024 * 32];
|
||||
|
||||
#define
|
||||
#define
|
||||
|
||||
typedef unsigned short tui16;
|
||||
|
||||
|
@ -1,266 +0,0 @@
|
||||
|
||||
|
||||
// not used
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "decoderthread.h"
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* o need to maintain aspect ratio while resizing
|
||||
* o clicking in the middle of the slider bar should move the slider to the middle
|
||||
* o need to be able to rewind the move when it is done playing
|
||||
* o need to be able to load another move and play it w/o restarting player
|
||||
* o pause button needs to work
|
||||
* o need images for btns
|
||||
*/
|
||||
|
||||
DecoderThread::DecoderThread()
|
||||
{
|
||||
channel = NULL;
|
||||
geometry.setX(0);
|
||||
geometry.setY(0);
|
||||
geometry.setWidth(0);
|
||||
geometry.setHeight(0);
|
||||
stream_id = 101;
|
||||
elapsedTime = 0;
|
||||
la_seekPos = -1;
|
||||
videoTimer = NULL;
|
||||
audioTimer = NULL;
|
||||
}
|
||||
|
||||
void DecoderThread::run()
|
||||
{
|
||||
/* need a media file */
|
||||
if (filename.length() == 0)
|
||||
{
|
||||
emit on_decoderErrorMsg("No media file",
|
||||
"Please select a media file to play");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DecoderThread::startMediaPlay()
|
||||
{
|
||||
MediaPacket *mediaPkt;
|
||||
int is_video_frame;
|
||||
int rv;
|
||||
|
||||
/* setup video timer; each time this timer fires, it sends */
|
||||
/* one video pkt to the client then resets the callback duration */
|
||||
videoTimer = new QTimer;
|
||||
connect(videoTimer, SIGNAL(timeout()), this, SLOT(videoTimerCallback()));
|
||||
//videoTimer->start(1500);
|
||||
|
||||
/* setup audio timer; does the same as above, but with audio pkts */
|
||||
audioTimer = new QTimer;
|
||||
connect(audioTimer, SIGNAL(timeout()), this, SLOT(audioTimerCallback()));
|
||||
//audioTimer->start(500);
|
||||
|
||||
/* setup pktTimer; each time this timer fires, it reads AVPackets */
|
||||
/* and puts them into audio/video Queues */
|
||||
pktTimer = new QTimer;
|
||||
connect(pktTimer, SIGNAL(timeout()), this, SLOT(pktTimerCallback()));
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* fill the audio/video queues with initial data; thereafter */
|
||||
/* data will be filled by pktTimerCallback() */
|
||||
if ((audioQueue.count() >= 3000) || (videoQueue.count() >= 3000))
|
||||
{
|
||||
//pktTimer->start(50);
|
||||
|
||||
//videoTimer->start(1500);
|
||||
//audioTimer->start(500);
|
||||
|
||||
playVideo = new PlayVideo(NULL, &videoQueue, channel, 101);
|
||||
playVideoThread = new QThread(this);
|
||||
connect(playVideoThread, SIGNAL(started()), playVideo, SLOT(play()));
|
||||
playVideo->moveToThread(playVideoThread);
|
||||
playVideoThread->start();
|
||||
|
||||
playAudio = new PlayAudio(NULL, &audioQueue, channel, 101);
|
||||
playAudioThread = new QThread(this);
|
||||
connect(playAudioThread, SIGNAL(started()), playAudio, SLOT(play()));
|
||||
playAudio->moveToThread(playAudioThread);
|
||||
playAudioThread->start();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mediaPkt = new MediaPacket;
|
||||
rv = xrdpvr_get_frame(&mediaPkt->av_pkt,
|
||||
&is_video_frame,
|
||||
&mediaPkt->delay_in_us);
|
||||
if (rv < 0)
|
||||
{
|
||||
/* looks like we reached end of file */
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_video_frame)
|
||||
videoQueue.enqueue(mediaPkt);
|
||||
else
|
||||
audioQueue.enqueue(mediaPkt);
|
||||
|
||||
} /* end while (1) */
|
||||
}
|
||||
|
||||
void DecoderThread::on_mediaSeek(int value)
|
||||
{
|
||||
mutex.lock();
|
||||
la_seekPos = value;
|
||||
mutex.unlock();
|
||||
|
||||
qDebug() << "media seek value=" << value;
|
||||
|
||||
/* pktTimer stops at end of media; need to restart it */
|
||||
if (!pktTimer->isActive())
|
||||
{
|
||||
updateSlider();
|
||||
pktTimer->start(100);
|
||||
}
|
||||
}
|
||||
|
||||
void DecoderThread::setFilename(QString filename)
|
||||
{
|
||||
this->filename = filename;
|
||||
}
|
||||
|
||||
void DecoderThread::stopPlayer()
|
||||
{
|
||||
pktTimer->stop();
|
||||
audioQueue.clear();
|
||||
videoQueue.clear();
|
||||
}
|
||||
|
||||
void DecoderThread::pausePlayer()
|
||||
{
|
||||
pktTimer->stop();
|
||||
}
|
||||
|
||||
void DecoderThread::resumePlayer()
|
||||
{
|
||||
pktTimer->start(100);
|
||||
}
|
||||
|
||||
void DecoderThread::close()
|
||||
{
|
||||
}
|
||||
|
||||
void DecoderThread::audioTimerCallback()
|
||||
{
|
||||
MediaPacket *pkt;
|
||||
int delayInMs;
|
||||
|
||||
if (audioQueue.isEmpty())
|
||||
{
|
||||
qDebug() << "audioTimerCallback: got empty";
|
||||
audioTimer->setInterval(100);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = audioQueue.dequeue();
|
||||
delayInMs = (int) ((float) pkt->delay_in_us / 1000.0);
|
||||
send_audio_pkt(channel, 101, pkt->av_pkt);
|
||||
delete pkt;
|
||||
|
||||
//qDebug() << "audioTimerCallback: delay :" << delayInMs;
|
||||
|
||||
audioTimer->setInterval(delayInMs);
|
||||
}
|
||||
|
||||
void DecoderThread::videoTimerCallback()
|
||||
{
|
||||
MediaPacket *pkt;
|
||||
int delayInMs;
|
||||
|
||||
if (videoQueue.isEmpty())
|
||||
{
|
||||
qDebug() << "videoTimerCallback: GOT EMPTY";
|
||||
videoTimer->setInterval(100);
|
||||
return;
|
||||
}
|
||||
|
||||
pkt = videoQueue.dequeue();
|
||||
delayInMs = (int) 10; // ((float) pkt->delay_in_us / 1000.0);
|
||||
send_video_pkt(channel, 101, pkt->av_pkt);
|
||||
delete pkt;
|
||||
updateSlider();
|
||||
//qDebug() << "videoTimerCallback: delay :" << delayInMs;
|
||||
videoTimer->setInterval(delayInMs);
|
||||
}
|
||||
|
||||
void DecoderThread::pktTimerCallback()
|
||||
{
|
||||
MediaPacket *mediaPkt;
|
||||
int is_video_frame;
|
||||
int rv;
|
||||
|
||||
while (1)
|
||||
{
|
||||
qDebug() << "pktTimerCallback: audioCount=" << audioQueue.count() << "videoCount=" << videoQueue.count();
|
||||
#if 1
|
||||
if ((audioQueue.count() >= 20) || (videoQueue.count() >= 20))
|
||||
return;
|
||||
#else
|
||||
if (videoQueue.count() >= 60)
|
||||
return;
|
||||
#endif
|
||||
mediaPkt = new MediaPacket;
|
||||
rv = xrdpvr_get_frame(&mediaPkt->av_pkt,
|
||||
&is_video_frame,
|
||||
&mediaPkt->delay_in_us);
|
||||
if (rv < 0)
|
||||
{
|
||||
/* looks like we reached end of file */
|
||||
qDebug() << "###### looks like we reached EOF";
|
||||
pktTimer->stop();
|
||||
// LK_TODO set some flag so audio/video timer also stop when q is empty
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_video_frame)
|
||||
videoQueue.enqueue(mediaPkt);
|
||||
else
|
||||
audioQueue.enqueue(mediaPkt);
|
||||
}
|
||||
}
|
||||
|
||||
void DecoderThread::updateSlider()
|
||||
{
|
||||
if (elapsedTime == 0)
|
||||
elapsedTime = av_gettime();
|
||||
|
||||
/* time elapsed in 1/100th sec units since play started */
|
||||
emit on_elapsedtime((av_gettime() - elapsedTime) / 10000);
|
||||
|
||||
mutex.lock();
|
||||
if (la_seekPos >= 0)
|
||||
{
|
||||
qDebug() << "seeking to" << la_seekPos;
|
||||
//audioTimer->stop();
|
||||
//videoTimer->stop();
|
||||
xrdpvr_seek_media(la_seekPos, 0);
|
||||
elapsedTime = av_gettime() - la_seekPos * 1000000;
|
||||
//audioTimer->start(10);
|
||||
//videoTimer->start(10);
|
||||
la_seekPos = -1;
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
#ifndef DECODERTHREAD_H
|
||||
#define DECODERTHREAD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#ifdef _STDINT_H
|
||||
#undef _STDINT_H
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include <QThread>
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QRect>
|
||||
#include <QMutex>
|
||||
#include <QTimer>
|
||||
#include <QQueue>
|
||||
|
||||
#include <xrdpapi.h>
|
||||
#include <xrdpvr.h>
|
||||
#include <mediapacket.h>
|
||||
#include <playvideo.h>
|
||||
#include <playaudio.h>
|
||||
|
||||
/* ffmpeg related stuff */
|
||||
extern "C"
|
||||
{
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
}
|
||||
|
||||
class DecoderThread : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/* public methods */
|
||||
DecoderThread();
|
||||
|
||||
void setFilename(QString filename);
|
||||
void stopPlayer();
|
||||
void pausePlayer();
|
||||
void resumePlayer();
|
||||
void oneTimeDeinit();
|
||||
void close();
|
||||
void run();
|
||||
void startMediaPlay();
|
||||
|
||||
public slots:
|
||||
void on_mediaSeek(int value);
|
||||
|
||||
private:
|
||||
/* private variables */
|
||||
QQueue<MediaPacket *> audioQueue;
|
||||
QQueue<MediaPacket *> videoQueue;
|
||||
|
||||
QTimer *videoTimer;
|
||||
QTimer *audioTimer;
|
||||
QTimer *pktTimer;
|
||||
QString filename;
|
||||
void *channel;
|
||||
int stream_id;
|
||||
QRect geometry;
|
||||
int64_t elapsedTime; /* elapsed time in usecs since play started */
|
||||
QMutex mutex;
|
||||
int64_t la_seekPos; /* locked access; must hold mutex */
|
||||
|
||||
PlayVideo *playVideo;
|
||||
QThread *playVideoThread;
|
||||
PlayAudio *playAudio;
|
||||
QThread *playAudioThread;
|
||||
|
||||
/* private functions */
|
||||
int sendMetadataFile();
|
||||
int sendAudioFormat();
|
||||
int sendVideoFormat();
|
||||
int sendGeometry();
|
||||
void updateSlider();
|
||||
|
||||
private slots:
|
||||
/* private slots */
|
||||
void audioTimerCallback();
|
||||
void videoTimerCallback();
|
||||
void pktTimerCallback();
|
||||
|
||||
signals:
|
||||
/* private signals */
|
||||
void on_progressUpdate(int percent);
|
||||
void on_decoderErrorMsg(QString title, QString msg);
|
||||
void on_mediaDurationInSeconds(int duration);
|
||||
void on_elapsedtime(int val); /* in hundredth of a sec */
|
||||
};
|
||||
|
||||
#endif // DECODERTHREAD_H
|
@ -11,6 +11,7 @@ OurInterface::OurInterface(QObject *parent) :
|
||||
savedGeometry.setHeight(0);
|
||||
stream_id = 101;
|
||||
demuxMedia = 0;
|
||||
demuxMediaThread = NULL;
|
||||
//elapsedTime = 0;
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ handle_connection(int client_fd)
|
||||
}
|
||||
if (retlen != sizeof(rdp_fd))
|
||||
{
|
||||
fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %d\n",
|
||||
fprintf(stderr, "WTSVirtualChannelQuery() returned wrong length %u\n",
|
||||
retlen);
|
||||
}
|
||||
rdp_fd = *retdata;
|
||||
|
Loading…
Reference in New Issue
Block a user