#include <stdio.h>
#include <windows.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/time.h>
#define SCREEN_WIDTH 1860
#define SCREEN_HEIGHT 930
void output_audio_frame(const AVFrame *frame) {
}
void write_frame(const AVFrame *frame) {
HBITMAP img = CreateBitmap(frame->width, frame->height, 1, 32, frame->data[0]);
HWND hwnd = GetConsoleWindow();
HDC hdc_cmd = GetDC(hwnd);
HDC hdc_img = CreateCompatibleDC(NULL);
HGDIOBJ obj_hdc = SelectObject(hdc_img, img);
BITMAP bm; GetObject(img, sizeof(BITMAP), &bm);
BitBlt(hdc_cmd, 0, 0, bm.bmWidth, bm.bmHeight, hdc_img, 0, 0, SRCCOPY);
SelectObject(hdc_img, obj_hdc);
DeleteDC(hdc_img);
ReleaseDC(hwnd, hdc_cmd);
DeleteObject(img);
}
void output_video_frame(const AVFrame *frame) {
int width = frame->width;
int height = frame->height;
struct SwsContext *sws_ctx = sws_getContext(width, height, frame->format, SCREEN_WIDTH, SCREEN_HEIGHT, \
AV_PIX_FMT_BGRA, SWS_FAST_BILINEAR, NULL, NULL, NULL);
AVFrame *frame_bgra = av_frame_alloc();
frame_bgra->format = AV_PIX_FMT_BGRA;
frame_bgra->width = SCREEN_WIDTH;
frame_bgra->height = SCREEN_HEIGHT;
av_frame_get_buffer(frame_bgra, 4);
sws_scale(sws_ctx, (const uint8_t *const *)frame->data, frame->linesize, 0, height, frame_bgra->data, \
frame_bgra->linesize);
write_frame(frame_bgra);
av_frame_free(&frame_bgra);
sws_freeContext(sws_ctx);
}
void decode_packet(AVCodecContext *dec_ctx, const AVPacket *packet) {
avcodec_send_packet(dec_ctx, packet);
AVFrame *frame = av_frame_alloc();
while(!avcodec_receive_frame(dec_ctx, frame)) {
if(dec_ctx->codec->type == AVMEDIA_TYPE_AUDIO) output_audio_frame(frame);
if(dec_ctx->codec->type == AVMEDIA_TYPE_VIDEO) output_video_frame(frame);
av_frame_unref(frame);
}
av_frame_free(&frame);
}
int main(void) {
const char *filename = "test.mp4";
AVFormatContext *fmt_ctx = NULL;
avformat_open_input(&fmt_ctx, filename, NULL, NULL);
avformat_find_stream_info(fmt_ctx, NULL);
av_dump_format(fmt_ctx, 0, filename, 0);
int audio_stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
int video_stream_idx = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
AVStream *audio_stream = fmt_ctx->streams[audio_stream_idx];
AVStream *video_stream = fmt_ctx->streams[video_stream_idx];
const AVCodec *audio_dec = avcodec_find_decoder(audio_stream->codecpar->codec_id);
const AVCodec *video_dec = avcodec_find_decoder(video_stream->codecpar->codec_id);
AVCodecContext *audio_dec_ctx = avcodec_alloc_context3(audio_dec);
AVCodecContext *video_dec_ctx = avcodec_alloc_context3(video_dec);
avcodec_parameters_to_context(audio_dec_ctx, audio_stream->codecpar);
avcodec_parameters_to_context(video_dec_ctx, video_stream->codecpar);
avcodec_open2(audio_dec_ctx, audio_dec, NULL);
avcodec_open2(video_dec_ctx, video_dec, NULL);
AVPacket *packet = av_packet_alloc();
int64_t start_time = av_gettime();
while(!av_read_frame(fmt_ctx, packet)) {
AVCodecContext *dec_ctx = NULL;
int stream_idx = packet->stream_index;
dec_ctx = stream_idx == audio_stream_idx ? audio_dec_ctx : dec_ctx;
dec_ctx = stream_idx == video_stream_idx ? video_dec_ctx : dec_ctx;
if(dec_ctx) decode_packet(dec_ctx, packet);
int64_t pts = av_rescale_q(packet->pts, fmt_ctx->streams[stream_idx]->time_base, \
av_make_q(1, AV_TIME_BASE));
int64_t now_time = av_gettime() - start_time;
if(pts > now_time) av_usleep(pts - now_time);
av_packet_unref(packet);
}
decode_packet(audio_dec_ctx, NULL);
decode_packet(video_dec_ctx, NULL);
av_packet_free(&packet);
avcodec_free_context(&video_dec_ctx);
avcodec_free_context(&audio_dec_ctx);
avformat_close_input(&fmt_ctx);
return 0;
}