mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-15 17:01:28 +00:00
New utility ivfrate(.exe) and a couple of small VP8 changes.
The command-line utility can query and set the frame rate of IVF files, since apparently encoders don't care too much about setting proper values in the IVF header. Also, add the utility to the synthesis build. On the playback side in EDuke32, get rid of the 1/(2*fps) "correction" if the FPS numerator is <1000 (presumably used in older encoders) and properly print the frame rate's fractional part. git-svn-id: https://svn.eduke32.com/eduke32@3131 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
parent
17bac8cb55
commit
b2162f554d
5 changed files with 158 additions and 29 deletions
|
@ -79,6 +79,8 @@ endif
|
|||
EDUKE32 ?= eduke32$(EXESUFFIX)
|
||||
MAPSTER32 ?= mapster32$(EXESUFFIX)
|
||||
|
||||
IVFRATE ?= ivfrate$(EXESUFFIX)
|
||||
|
||||
EDUKE32_TARGET:=$(EDUKE32)
|
||||
ifneq ($(PLATFORM),WII)
|
||||
MAPSTER32_TARGET:=$(MAPSTER32)
|
||||
|
@ -440,6 +442,11 @@ $(OBJ)/%.$o: $(SRC)/%.c
|
|||
$(COMPILE_STATUS)
|
||||
if $(COMPILER) $(OURCFLAGS) -c $< -o $@; then $(COMPILE_OK); else $(COMPILE_FAILED); fi
|
||||
|
||||
#### Utilities
|
||||
|
||||
$(IVFRATE): $(SRC)/ivfrate.c
|
||||
if $(COMPILER) -Wall -Wextra $< -o $@; then $(COMPILE_OK); else $(COMPILE_FAILED); fi
|
||||
|
||||
#### Lunatic
|
||||
|
||||
# Create object files directly with luajit
|
||||
|
|
|
@ -26,29 +26,22 @@ const char *animvpx_read_ivf_header_errmsg[] = {
|
|||
"unrecognized IVF version, expected 0",
|
||||
"only VP8 video stream supported",
|
||||
"invalid framerate numerator or denominator after correction, must not be 0",
|
||||
"INTERNAL ERROR, IVF header size wrong"
|
||||
};
|
||||
|
||||
int32_t animvpx_read_ivf_header(int32_t inhandle, animvpx_ivf_header_t *hdr)
|
||||
{
|
||||
if (sizeof(animvpx_ivf_header_t) != 32)
|
||||
return 6;
|
||||
int32_t err;
|
||||
|
||||
Bassert(sizeof(animvpx_ivf_header_t) == 32);
|
||||
|
||||
if (kread(inhandle, hdr, sizeof(animvpx_ivf_header_t)) != sizeof(animvpx_ivf_header_t))
|
||||
return 1; // "couldn't read header"
|
||||
|
||||
if (Bmemcmp(hdr,"DKIF",4))
|
||||
return 2; // "not an IVF file"
|
||||
|
||||
hdr->version = B_LITTLE16(hdr->version);
|
||||
if (hdr->version != 0)
|
||||
return 3; // "unrecognized IVF version"
|
||||
err = animvpx_check_header(hdr);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hdr->hdrlen = B_LITTLE16(hdr->hdrlen);
|
||||
// fourcc is left as-is
|
||||
|
||||
if (Bmemcmp(hdr->fourcc, "VP80", 4))
|
||||
return 4; // "only VP8 supported"
|
||||
|
||||
hdr->width = B_LITTLE16(hdr->width);
|
||||
hdr->height = B_LITTLE16(hdr->height);
|
||||
|
@ -59,30 +52,21 @@ int32_t animvpx_read_ivf_header(int32_t inhandle, animvpx_ivf_header_t *hdr)
|
|||
|
||||
// the rest is based on vpxdec.c --> file_is_ivf()
|
||||
|
||||
/* Some versions of vpxenc used 1/(2*fps) for the timebase, so
|
||||
* we can guess the framerate using only the timebase in this
|
||||
* case. Other files would require reading ahead to guess the
|
||||
* timebase, like we do for webm.
|
||||
*/
|
||||
if (hdr->fpsnumer < 1000)
|
||||
{
|
||||
/* Correct for the factor of 2 applied to the timebase in the
|
||||
* encoder.
|
||||
*/
|
||||
if (hdr->fpsnumer&1)
|
||||
hdr->fpsdenom <<= 1;
|
||||
else
|
||||
hdr->fpsnumer >>= 1;
|
||||
// NOTE: We got rid of the 1/(2*fps) correction from libvpx's vpxdec.c,
|
||||
// users are encouraged to use the "ivfrate" utility from the source/
|
||||
// directory instead.
|
||||
|
||||
if (hdr->fpsdenom==0 || hdr->fpsnumer==0)
|
||||
return 5; // "invalid framerate numerator or denominator"
|
||||
|
||||
initprintf("animvpx: rate is %d frames / %d seconds (%.03f fps) after 1/(2*fps) correction.\n",
|
||||
initprintf("animvpx: rate is %d frames / %d seconds (%.03f fps).\n",
|
||||
hdr->fpsnumer, hdr->fpsdenom, (double)hdr->fpsnumer/hdr->fpsdenom);
|
||||
}
|
||||
else
|
||||
{
|
||||
double fps = (hdr->fpsdenom==0) ? 0.0 : hdr->fpsnumer/hdr->fpsdenom;
|
||||
double fps = (hdr->fpsdenom==0) ? 0.0 : (double)hdr->fpsnumer/hdr->fpsdenom;
|
||||
|
||||
initprintf("animvpx: set rate to 30 fps (header says %d frames / %d seconds = %.03f fps).\n",
|
||||
hdr->fpsnumer, hdr->fpsdenom, fps);
|
||||
|
|
|
@ -86,5 +86,19 @@ int32_t animvpx_render_frame(animvpx_codec_ctx *codec);
|
|||
|
||||
void animvpx_print_stats(const animvpx_codec_ctx *codec);
|
||||
|
||||
static inline int32_t animvpx_check_header(const animvpx_ivf_header_t *hdr)
|
||||
{
|
||||
if (Bmemcmp(hdr->magic,"DKIF",4))
|
||||
return 2; // "not an IVF file"
|
||||
|
||||
if (hdr->version != 0)
|
||||
return 3; // "unrecognized IVF version"
|
||||
|
||||
// fourcc is left as-is
|
||||
if (Bmemcmp(hdr->fourcc, "VP80", 4))
|
||||
return 4; // "only VP8 supported"
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // !defined ANIM_VPX_H
|
||||
|
|
124
polymer/eduke32/source/ivfrate.c
Normal file
124
polymer/eduke32/source/ivfrate.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#define Bmemcmp memcmp
|
||||
#define USE_OPENGL
|
||||
#include "animvpx.h"
|
||||
|
||||
|
||||
static void print_info(const char *prefix, const animvpx_ivf_header_t *hdr)
|
||||
{
|
||||
printf("%s%d x %d, %d frames @ %d frames / %d seconds (%.3f fps%s)\n", prefix,
|
||||
hdr->width, hdr->height, hdr->numframes, hdr->fpsnumer, hdr->fpsdenom,
|
||||
(hdr->fpsdenom==0 ? 0 : (double)hdr->fpsnumer/hdr->fpsdenom),
|
||||
hdr->fpsnumer>=1000 ? " --> 30 fps" : "");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd, dowrite, err;
|
||||
animvpx_ivf_header_t hdr;
|
||||
|
||||
union { uint16_t i; char c[2]; } u;
|
||||
u.c[0] = 1;
|
||||
u.c[1] = 0;
|
||||
if (u.i != 1)
|
||||
{
|
||||
fprintf(stderr, "This program is only for little-endian machines.\n");
|
||||
return 255;
|
||||
}
|
||||
|
||||
if (argc != 2 && argc != 4 && argc != 5)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s <file.ivf> [<fpsnumerator> <fpsdenominator> [-force]]\n"
|
||||
" Without -force, <fpsnumerator> must be < 1000.\n"
|
||||
" If <fpsnumerator> is >= 1000, the actual frame rate\n"
|
||||
" is set to 30 fps on playback.\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dowrite = (argc >= 4);
|
||||
|
||||
fd = open(argv[1], dowrite ? O_RDWR : O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
fprintf(stderr, "Could't open \"%s\" for: %s\n",
|
||||
dowrite ? "reading/writing":"reading", strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
|
||||
{
|
||||
fprintf(stderr, "Couldn't read IVF header: %s\n", strerror(errno));
|
||||
return 3;
|
||||
}
|
||||
|
||||
err = animvpx_check_header(&hdr);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "Header check failed with code %d (not an IVF file?)\n", err);
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (!dowrite)
|
||||
{
|
||||
print_info("", &hdr);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned long numer = strtoul(argv[2], NULL, 10);
|
||||
unsigned long denom = strtoul(argv[3], NULL, 10);
|
||||
uint32_t numer32=numer, denom32=denom;
|
||||
const int NUMER_OFS = offsetof(animvpx_ivf_header_t, fpsnumer);
|
||||
|
||||
if (denom == 0)
|
||||
{
|
||||
fprintf(stderr, "FPS denominator must not be zero!\n");
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (numer >= 1000 && (argc!=5 || strcmp(argv[4], "-force")))
|
||||
{
|
||||
fprintf(stderr, "FPS numerator must be < 1000, or -force must be passed as 5th arg.\n");
|
||||
return 5;
|
||||
}
|
||||
|
||||
if (numer32 != numer || denom32 != denom)
|
||||
{
|
||||
fprintf(stderr, "Out of range number passed.\n");
|
||||
return 6;
|
||||
}
|
||||
|
||||
print_info("Old: ", &hdr);
|
||||
hdr.fpsnumer = numer32;
|
||||
hdr.fpsdenom = denom32;
|
||||
print_info("New: ", &hdr);
|
||||
|
||||
if (lseek(fd, NUMER_OFS, SEEK_SET) != NUMER_OFS)
|
||||
{
|
||||
fprintf(stderr, "lseek failed: %s\n", strerror(errno));
|
||||
return 7;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
err |= (write(fd, &numer32, 4) != 4);
|
||||
err |= (write(fd, &denom32, 4) != 4);
|
||||
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "Warning: data not fully written.\n");
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -9,8 +9,8 @@ make=( make PLATFORM=WINDOWS CC='wine gcc' CXX='wine g++' AS='wine nasm' RC='win
|
|||
clean=veryclean
|
||||
|
||||
# the following file paths are relative to $source
|
||||
targets=( eduke32.exe mapster32.exe )
|
||||
bin_packaged=( eduke32.exe eduke32.debug.exe mapster32.exe mapster32.debug.exe ebacktrace1.dll SEHELP.HLP STHELP.HLP names.h buildlic.txt GNU.TXT m32help.hlp nedmalloc.dll tiles.cfg samples/* )
|
||||
targets=( eduke32.exe mapster32.exe ivfrate.exe )
|
||||
bin_packaged=( eduke32.exe eduke32.debug.exe mapster32.exe mapster32.debug.exe ivfrate.exe ebacktrace1.dll SEHELP.HLP STHELP.HLP names.h buildlic.txt GNU.TXT m32help.hlp nedmalloc.dll tiles.cfg samples/* )
|
||||
not_src_packaged=( psd source/jaudiolib/third-party/vorbis.framework/Versions/A/vorbis Apple/lib )
|
||||
|
||||
# group that owns the resulting packages
|
||||
|
|
Loading…
Reference in a new issue