Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Commit

Permalink
consider struct over static variables and consider struct as referenc…
Browse files Browse the repository at this point in the history
…e input arg for functions
  • Loading branch information
MGTheTrain committed Apr 19, 2024
1 parent 033d918 commit e9f8d4a
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 175 deletions.
12 changes: 7 additions & 5 deletions apps/video-player/src/video-player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,22 @@ int main(int argc, char* argv[]) {

const char* videoFileName = argv[1];

if (!initVideoPlayer()) {
VideoPlayer player;

if (!initVideoPlayer(player)) {
std::cerr << "Failed to initialize video player\n";
return -1;
}

if (!loadVideo(videoFileName)) {
if (!loadVideo(player, videoFileName)) {
std::cerr << "Failed to load video: " << videoFileName << "\n";
closeVideoPlayer();
closeVideoPlayer(player);
return -1;
}

playVideo();
playVideo(player);

closeVideoPlayer();
closeVideoPlayer(player);

return 0;
}
Expand Down
35 changes: 19 additions & 16 deletions modules/video/include/video.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,26 @@ extern "C" {
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#endif
static AVFormatContext* formatContext = nullptr;
static AVCodecParameters* codecParameters = nullptr;
static const AVCodec* codec = nullptr;
static AVCodecContext* codecContext = nullptr;
static SDL_Window* window = nullptr;
static SDL_Renderer* renderer = nullptr;
static SDL_Texture* texture = nullptr;
static struct SwsContext* swsContext = nullptr;
static AVFrame* frame = nullptr;
static int videoStream = -1;
static AVRational timeBase;
static double frameDuration;

bool initVideoPlayer();
bool loadVideo(const char* filename);
void playVideo();
void closeVideoPlayer();
struct VideoPlayer {
AVFormatContext* formatContext = nullptr;
AVCodecParameters* codecParameters = nullptr;
AVCodecContext* codecContext = nullptr;
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
SDL_Texture* texture = nullptr;
struct SwsContext* swsContext = nullptr;
AVFrame* frame = nullptr;
int videoStream = -1;
AVRational timeBase;
double frameDuration;
};

bool initVideoPlayer(VideoPlayer& player);
bool loadVideo(VideoPlayer& player, const char* filename);
void playVideo(VideoPlayer& player);
void closeVideoPlayer(VideoPlayer& player);

#ifdef __cplusplus
}
#endif
7 changes: 2 additions & 5 deletions modules/video/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,17 @@ project(${TARGET})
find_package(FFMPEG REQUIRED)
find_package(SDL2 CONFIG REQUIRED)

include_directories(${PROJECT_SOURCE_DIR}/../include)
include_directories(${PROJECT_SOURCE_DIR}/../include
${FFMPEG_INCLUDE_DIRS})

set(VIDEO_SRC
video.cpp
)

add_library(${TARGET} STATIC ${VIDEO_SRC})
target_include_directories(${TARGET} PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_directories(${TARGET} PRIVATE ${FFMPEG_LIBRARY_DIRS})
target_link_libraries(${TARGET} PRIVATE ${FFMPEG_LIBRARIES} SDL2::SDL2-static)

add_library(${TARGET}_wrapper SHARED ${VIDEO_SRC}) # required for bindings
target_include_directories(${TARGET}_wrapper PRIVATE ${FFMPEG_INCLUDE_DIRS})
target_link_directories(${TARGET}_wrapper PRIVATE ${FFMPEG_LIBRARY_DIRS})
target_link_libraries(${TARGET}_wrapper PRIVATE ${FFMPEG_LIBRARIES} SDL2::SDL2-static)

install(TARGETS ${TARGET} ${TARGET}_wrapper)
265 changes: 132 additions & 133 deletions modules/video/src/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,147 +22,146 @@

#include <video.h>

bool initVideoPlayer() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL initialization failed: " << SDL_GetError() << "\n";
return false;
}

// av_register_all();
if (avformat_network_init() < 0) {
std::cerr << "Failed to initialize FFmpeg network\n";
return false;
}

return true;
bool initVideoPlayer(VideoPlayer& player) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL initialization failed: " << SDL_GetError() << "\n";
return false;
}

if (avformat_network_init() < 0) {
std::cerr << "Failed to initialize FFmpeg network\n";
return false;
}

return true;
}

bool loadVideo(const char* filename) {
if (avformat_open_input(&formatContext, filename, NULL, NULL) != 0) {
std::cerr << "Couldn't open video file\n";
return false;
}

if (avformat_find_stream_info(formatContext, NULL) < 0) {
std::cerr << "Couldn't find stream information\n";
return false;
}

videoStream = -1;
for (int i = 0; i < formatContext->nb_streams; i++) {
if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
break;
bool loadVideo(VideoPlayer& player, const char* filename) {
if (avformat_open_input(&player.formatContext, filename, NULL, NULL) != 0) {
std::cerr << "Couldn't open video file\n";
return false;
}

if (avformat_find_stream_info(player.formatContext, NULL) < 0) {
std::cerr << "Couldn't find stream information\n";
return false;
}

player.videoStream = -1;
for (int i = 0; i < player.formatContext->nb_streams; i++) {
if (player.formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
player.videoStream = i;
break;
}
}

if (player.videoStream == -1) {
std::cerr << "Couldn't find a video stream\n";
return false;
}
}

if (videoStream == -1) {
std::cerr << "Couldn't find a video stream\n";
return false;
}

codecParameters = formatContext->streams[videoStream]->codecpar;
codec = avcodec_find_decoder(codecParameters->codec_id);
if (!codec) {
std::cerr << "Unsupported codec\n";
return false;
}

codecContext = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(codecContext, codecParameters) < 0) {
std::cerr << "Failed to copy codec parameters to codec context\n";
return false;
}

if (avcodec_open2(codecContext, codec, NULL) < 0) {
std::cerr << "Failed to open codec\n";
return false;
}

window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, codecContext->width,
codecContext->height,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if (!window) {
std::cerr << "Failed to create SDL window: " << SDL_GetError() << "\n";
return false;
}

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (!renderer) {
std::cerr << "Failed to create SDL renderer: " << SDL_GetError() << "\n";
return false;
}

texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING, codecContext->width,
codecContext->height);
if (!texture) {
std::cerr << "Failed to create SDL texture: " << SDL_GetError() << "\n";
return false;
}

swsContext = sws_getContext(codecContext->width, codecContext->height,
codecContext->pix_fmt, codecContext->width,
codecContext->height, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, NULL, NULL, NULL);
if (!swsContext) {
std::cerr << "Failed to create SwsContext\n";
return false;
}

timeBase = formatContext->streams[videoStream]->time_base;
frameDuration = av_q2d(timeBase);

return true;

player.codecParameters = player.formatContext->streams[player.videoStream]->codecpar;
const AVCodec* codec = avcodec_find_decoder(player.codecParameters->codec_id);
if (!codec) {
std::cerr << "Unsupported codec\n";
return false;
}

player.codecContext = avcodec_alloc_context3(codec);
if (avcodec_parameters_to_context(player.codecContext, player.codecParameters) < 0) {
std::cerr << "Failed to copy codec parameters to codec context\n";
return false;
}

if (avcodec_open2(player.codecContext, codec, NULL) < 0) {
std::cerr << "Failed to open codec\n";
return false;
}

player.window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, player.codecContext->width,
player.codecContext->height,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if (!player.window) {
std::cerr << "Failed to create SDL window: " << SDL_GetError() << "\n";
return false;
}

player.renderer = SDL_CreateRenderer(player.window, -1, SDL_RENDERER_ACCELERATED);
if (!player.renderer) {
std::cerr << "Failed to create SDL renderer: " << SDL_GetError() << "\n";
return false;
}

player.texture = SDL_CreateTexture(player.renderer, SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING, player.codecContext->width,
player.codecContext->height);
if (!player.texture) {
std::cerr << "Failed to create SDL texture: " << SDL_GetError() << "\n";
return false;
}

player.swsContext = sws_getContext(player.codecContext->width, player.codecContext->height,
player.codecContext->pix_fmt, player.codecContext->width,
player.codecContext->height, AV_PIX_FMT_YUV420P,
SWS_BILINEAR, NULL, NULL, NULL);
if (!player.swsContext) {
std::cerr << "Failed to create SwsContext\n";
return false;
}

player.timeBase = player.formatContext->streams[player.videoStream]->time_base;
player.frameDuration = av_q2d(player.timeBase);

return true;
}

void playVideo() {
AVPacket packet;
Uint32 previousFrameTime = SDL_GetTicks();

while (av_read_frame(formatContext, &packet) >= 0) {
if (packet.stream_index == videoStream) {
if (avcodec_send_packet(codecContext, &packet) < 0) {
std::cerr << "Error sending a packet for decoding\n";
continue;
}

if (avcodec_receive_frame(codecContext, frame) == 0) {
sws_scale(swsContext, frame->data, frame->linesize, 0, frame->height,
frame->data, frame->linesize);

SDL_UpdateYUVTexture(texture, nullptr, frame->data[0],
frame->linesize[0], frame->data[1],
frame->linesize[1], frame->data[2],
frame->linesize[2]);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, nullptr, nullptr);
SDL_RenderPresent(renderer);

Uint32 currentFrameTime = SDL_GetTicks();
Uint32 elapsedTime = currentFrameTime - previousFrameTime;
previousFrameTime = currentFrameTime;

int desiredDelay = (int)(frameDuration * 1000) - elapsedTime;

if (desiredDelay > 0) {
SDL_Delay(desiredDelay);
void playVideo(VideoPlayer& player) {
AVPacket packet;
Uint32 previousFrameTime = SDL_GetTicks();

while (av_read_frame(player.formatContext, &packet) >= 0) {
if (packet.stream_index == player.videoStream) {
if (avcodec_send_packet(player.codecContext, &packet) < 0) {
std::cerr << "Error sending a packet for decoding\n";
continue;
}

if (avcodec_receive_frame(player.codecContext, player.frame) == 0) {
sws_scale(player.swsContext, player.frame->data, player.frame->linesize, 0, player.frame->height,
player.frame->data, player.frame->linesize);

SDL_UpdateYUVTexture(player.texture, nullptr, player.frame->data[0],
player.frame->linesize[0], player.frame->data[1],
player.frame->linesize[1], player.frame->data[2],
player.frame->linesize[2]);
SDL_RenderClear(player.renderer);
SDL_RenderCopy(player.renderer, player.texture, nullptr, nullptr);
SDL_RenderPresent(player.renderer);

Uint32 currentFrameTime = SDL_GetTicks();
Uint32 elapsedTime = currentFrameTime - previousFrameTime;
previousFrameTime = currentFrameTime;

int desiredDelay = (int)(player.frameDuration * 1000) - elapsedTime;

if (desiredDelay > 0) {
SDL_Delay(desiredDelay);
}
}
}
}
av_packet_unref(&packet);
}
av_packet_unref(&packet);
}
}

void closeVideoPlayer() {
SDL_DestroyTexture(texture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
void closeVideoPlayer(VideoPlayer& player) {
SDL_DestroyTexture(player.texture);
SDL_DestroyRenderer(player.renderer);
SDL_DestroyWindow(player.window);
SDL_Quit();

av_frame_free(&frame);
avcodec_close(codecContext);
avformat_close_input(&formatContext);
avformat_network_deinit();
av_frame_free(&player.frame);
avcodec_close(player.codecContext);
avformat_close_input(&player.formatContext);
avformat_network_deinit();
}
Loading

0 comments on commit e9f8d4a

Please sign in to comment.