/stkok.c Secret
Created
July 12, 2021 15:20
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// gcc -o video video.c -lavcodec -lavformat -lavutil -lavdevice -pthread | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <errno.h> | |
#include <assert.h> | |
#include <threads.h> | |
#include <unistd.h> | |
#include <libavformat/avformat.h> | |
#include <libavdevice/avdevice.h> | |
#include <libavutil/pixdesc.h> | |
int av_die(const char* info1, const char* info2, const char* msg, int err) | |
{ | |
char buffer[256]; | |
av_strerror(err, buffer, sizeof buffer); | |
printf("%s, %s, %s, %s", info1, info2, msg, buffer); | |
exit(1); | |
return 0; | |
} | |
int M_ERC; | |
#define M_XSTR(s) M_STR(s) | |
#define M_STR(s) #s | |
#define AV_TRY(x) ((M_ERC = (x)) < 0 ? av_die(M_XSTR(__LINE__), __FILE__, #x, M_ERC) : M_ERC) | |
mtx_t video_lock; | |
void *video_data; | |
int main(int argc, char *argv[]) | |
{ | |
mtx_init(&video_lock, mtx_plain); | |
avdevice_register_all(); | |
AVInputFormat *input_format = av_find_input_format("video4linux2"); | |
assert(input_format); | |
AVFormatContext *ctx = avformat_alloc_context(); | |
ctx->flags = AVFMT_FLAG_NONBLOCK; | |
AV_TRY(avformat_open_input(&ctx, "/dev/video0", input_format, NULL)); | |
assert(ctx); | |
AVCodec *codec = NULL; | |
AVStream *stream = NULL; | |
int stream_index = AV_TRY(av_find_best_stream(ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0)); | |
assert(codec); | |
stream = ctx->streams[stream_index]; | |
assert(stream); | |
AVCodecContext *codec_ctx = NULL; | |
codec_ctx = avcodec_alloc_context3(codec); | |
assert(codec_ctx); | |
AV_TRY(avcodec_parameters_to_context(codec_ctx, stream->codecpar)); | |
AVDictionary *codec_opts = NULL; | |
av_dict_set(&codec_opts, "refcounted_frames", "1", 0); | |
assert(codec_opts); | |
AV_TRY(avcodec_open2(codec_ctx, codec, &codec_opts)); | |
assert(!av_dict_count(codec_opts)); | |
AVFrame *frame = av_frame_alloc(); | |
AVPacket *packet = av_packet_alloc(); | |
int ret; | |
while (1) | |
{ | |
while ((ret = avcodec_receive_frame(codec_ctx, frame)) == 0) | |
{ | |
assert(frame->width == 720); | |
assert(frame->height == 480); | |
assert(frame->format == AV_PIX_FMT_UYVY422); | |
mtx_lock(&video_lock); | |
if (!video_data) | |
free(video_data); | |
video_data = malloc(frame->linesize[0] * frame->height); | |
memcpy(video_data, frame->data[0], frame->linesize[0] * frame->height); | |
mtx_unlock(&video_lock); | |
av_frame_unref(frame); | |
} | |
if (ret == AVERROR(EAGAIN)) | |
{ | |
while (1) | |
{ | |
ret = av_read_frame(ctx, packet); | |
if (ret != 0) | |
break; | |
if (packet->stream_index == stream_index) | |
break; | |
av_packet_unref(packet); | |
} | |
if (ret == AVERROR(EAGAIN)) { | |
usleep(500); | |
continue; | |
} | |
if (ret != 0) { | |
printf("failed to receive frame\n"); | |
continue; | |
} | |
ret = avcodec_send_packet(codec_ctx, packet); | |
if (ret != 0) | |
printf("decoding error\n"); | |
av_packet_unref(packet); | |
} | |
else if (ret == AVERROR_EOF) | |
{ | |
break; | |
} | |
else | |
{ | |
av_die("decoding error", "", "avcodec_receive_frame", ret); | |
} | |
} | |
if (!video_data) | |
free(video_data); | |
av_frame_free(&frame); | |
av_packet_free(&packet); | |
avcodec_free_context(&codec_ctx); | |
avformat_close_input(&ctx); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment