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