media validator
This commit is contained in:
commit
32892e729e
37
Makefile
Normal file
37
Makefile
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
RM := rm -f
|
||||||
|
CC := gcc
|
||||||
|
CFLAGS := -O3 -Wall -Isrc -I/usr/include/ffmpeg
|
||||||
|
LIBS := -lavformat -lavutil -lavcodec
|
||||||
|
LDFLAGS :=
|
||||||
|
INSTALL ?= install
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
|
||||||
|
COMMON_OBJECTS := build/validation.o
|
||||||
|
MEDIASTAT_OBJECTS := build/stat.o
|
||||||
|
|
||||||
|
# Phony rules
|
||||||
|
.PHONY: all mediastat clean
|
||||||
|
|
||||||
|
all: mediastat
|
||||||
|
|
||||||
|
install: all
|
||||||
|
$(INSTALL) build/mediastat $(PREFIX)/bin/mediastat
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
$(RM) -rf $(PREFIX)/bin/mediastat
|
||||||
|
|
||||||
|
mediastat: build/mediastat
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(COMMON_OBJECTS) $(MEDIASTAT_OBJECTS)
|
||||||
|
|
||||||
|
# Build rules
|
||||||
|
build/mediastat: $(COMMON_OBJECTS) $(MEDIASTAT_OBJECTS)
|
||||||
|
$(CC) $^ $(LDFLAGS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
build/%.o: src/%.c
|
||||||
|
$(CC) $(CFLAGS) -MMD -c $< -o $@
|
||||||
|
|
||||||
|
# Declare dependencies
|
||||||
|
-include $(COMMON_OBJECTS:.o=.d)
|
||||||
|
-include $(MEDIASTAT_OBJECTS:.o=.d)
|
3
build/.gitignore
vendored
Normal file
3
build/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
!.gitignore
|
80
src/stat.c
Normal file
80
src/stat.c
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "validation.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
AVFormatContext *format = NULL;
|
||||||
|
struct stat statbuf;
|
||||||
|
AVPacket pkt;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("No input specified\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
av_log_set_level(AV_LOG_QUIET);
|
||||||
|
|
||||||
|
if (stat(argv[1], &statbuf) != 0) {
|
||||||
|
printf("Couldn't read file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avformat_open_input(&format, argv[1], NULL, NULL) != 0) {
|
||||||
|
printf("Couldn't read file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mediatools_validate_video(format)) {
|
||||||
|
// Error is printed by validation function
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (av_seek_frame(format, -1, 0, AVSEEK_FLAG_BACKWARD) != 0) {
|
||||||
|
printf("Couldn't read file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vstream_idx = av_find_best_stream(format, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
|
||||||
|
if (vstream_idx < 0) {
|
||||||
|
printf("Couldn't read file\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t frames = 0;
|
||||||
|
int64_t last_pts = 0;
|
||||||
|
int last_stream = 0;
|
||||||
|
|
||||||
|
while (av_read_frame(format, &pkt) >= 0) {
|
||||||
|
int64_t new_pts = pkt.pts + pkt.duration;
|
||||||
|
|
||||||
|
if (last_pts < new_pts) {
|
||||||
|
last_pts = new_pts;
|
||||||
|
last_stream = pkt.stream_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pkt.stream_index == vstream_idx)
|
||||||
|
++frames;
|
||||||
|
|
||||||
|
av_packet_unref(&pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
AVRational tb = format->streams[last_stream]->time_base;
|
||||||
|
AVRational dur = av_mul_q(av_make_q(last_pts, 1), tb);
|
||||||
|
|
||||||
|
if (!mediatools_validate_duration(dur))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
AVCodecParameters *vpar = format->streams[vstream_idx]->codecpar;
|
||||||
|
|
||||||
|
printf("%ld %lu %d %d %d %d\n", statbuf.st_size, frames, vpar->width, vpar->height, dur.num, dur.den);
|
||||||
|
|
||||||
|
avformat_close_input(&format);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
91
src/validation.c
Normal file
91
src/validation.c
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "validation.h"
|
||||||
|
|
||||||
|
const AVRational t_1h = { 3600, 1 };
|
||||||
|
const AVRational t_0h = { 0, 1 };
|
||||||
|
|
||||||
|
int mediatools_validate_video(AVFormatContext *format)
|
||||||
|
{
|
||||||
|
uint64_t num_vstreams = 0;
|
||||||
|
uint64_t num_astreams = 0;
|
||||||
|
int64_t vstream_idx = -1;
|
||||||
|
int64_t astream_idx = -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < format->nb_streams; ++i) {
|
||||||
|
if (format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||||
|
num_vstreams++;
|
||||||
|
vstream_idx = i;
|
||||||
|
}
|
||||||
|
if (format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
|
||||||
|
num_astreams++;
|
||||||
|
astream_idx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_vstreams != 1) {
|
||||||
|
printf("Found %lu video streams (must be 1)\n", num_vstreams);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_astreams > 1) {
|
||||||
|
printf("Found %lu audio streams (must be 0 or 1)\n", num_astreams);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVInputFormat *iformat = format->iformat;
|
||||||
|
AVCodecParameters *vpar = format->streams[vstream_idx]->codecpar;
|
||||||
|
AVCodecParameters *apar = NULL;
|
||||||
|
|
||||||
|
if (astream_idx != -1)
|
||||||
|
apar = format->streams[astream_idx]->codecpar;
|
||||||
|
|
||||||
|
if (strstr(iformat->name, "matroska")) {
|
||||||
|
switch (vpar->codec_id) {
|
||||||
|
default:
|
||||||
|
printf("Bad video codec for WebM container (must be VP8, or VP9)\n");
|
||||||
|
return false;
|
||||||
|
case AV_CODEC_ID_VP8:
|
||||||
|
case AV_CODEC_ID_VP9:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apar) {
|
||||||
|
switch (apar->codec_id) {
|
||||||
|
default:
|
||||||
|
printf("Bad audio codec for WebM container (must be Opus or Vorbis)\n");
|
||||||
|
return false;
|
||||||
|
case AV_CODEC_ID_VORBIS:
|
||||||
|
case AV_CODEC_ID_OPUS:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Unknown input format\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vpar->width < 32 || vpar->width > 4096) {
|
||||||
|
printf("Bad width %d (must be 32..4096)\n", vpar->width);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vpar->height < 32 || vpar->height > 4096) {
|
||||||
|
printf("Bad height %d (must be 32..4096)\n", vpar->height);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mediatools_validate_duration(AVRational dur)
|
||||||
|
{
|
||||||
|
if (av_cmp_q(dur, t_0h) < 0 || av_cmp_q(dur, t_1h) > 0) {
|
||||||
|
printf("Bad duration (must be 0..1 hour)\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
9
src/validation.h
Normal file
9
src/validation.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef _VALIDATION_H_DEFINED
|
||||||
|
#define _VALIDATION_H_DEFINED
|
||||||
|
|
||||||
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
|
int mediatools_validate_video(AVFormatContext *format);
|
||||||
|
int mediatools_validate_duration(AVRational dur);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue