Video File Playback

[中文]

1. Overview

This section describes how to play video files on BK7258, including supported containers/codecs, key Kconfig options, the playback pipeline, and how to use the sample project.

Two API layers are provided:

  • Engine API: single-file playback control (play/stop/pause/seek/ff/rewind, etc.)

  • Playlist API: playlist management, track switching, and play modes on top of Engine

2. Supported features

  • Containers: AVI, MP4 (enable parsers via Kconfig)

  • Video: MJPEG, H264 (depending on decoder support)

  • Audio: PCM, AAC, etc. (depending on decoder support)

  • Controls: play/stop/pause/resume, seek, fast forward/rewind, volume/mute (requires upper-layer callbacks)

  • Queries: media info (duration, file size, audio/video parameters)

4. Kconfig options

Player Kconfig:

  • ap/components/bk_video_player/Kconfig

Common options (partial list):

  • CONFIG_AVI_PLAYER: enable the player component

  • CONFIG_BK_VIDEO_PLAYER_ENABLE_AVI_PARSER: enable AVI container parser

  • CONFIG_BK_VIDEO_PLAYER_ENABLE_MP4_PARSER: enable MP4 container parser

  • CONFIG_BK_VIDEO_PLAYER_ENABLE_AAC_DECODER: enable AAC audio decoder

  • CONFIG_BK_VIDEO_PLAYER_ENABLE_HW_JPEG_DECODER: enable HW JPEG (MJPEG) video decoder

  • CONFIG_BK_VIDEO_PLAYER_ENABLE_SW_JPEG_DECODER: enable SW JPEG (MJPEG) video decoder

Threads and stack sizes (see Kconfig for defaults):

  • CONFIG_BK_VIDEO_PLAYER_VIDEO_PARSE_THREAD_STACK_SIZE (vp_video_parse)

  • CONFIG_BK_VIDEO_PLAYER_AUDIO_PARSE_THREAD_STACK_SIZE (vp_audio_parse)

  • CONFIG_BK_VIDEO_PLAYER_VIDEO_DECODE_THREAD_STACK_SIZE (video_decode)

  • CONFIG_BK_VIDEO_PLAYER_AUDIO_DECODE_THREAD_STACK_SIZE (audio_decode)

  • CONFIG_BK_VIDEO_PLAYER_EVENT_THREAD_STACK_SIZE (vp_evt)

Note

The pipeline includes demux, decode, display, and audio output. PSRAM and sufficient heap are recommended. For stutter, corruption, or A/V sync issues, try lowering resolution, reducing pipeline buffer counts, increasing key stack sizes, and reducing logging.

5. Typical playback pipeline

Video player pipeline

Typical video file playback pipeline (Video Player pipeline)

  • Container parser: reads encoded audio/video packets from file

  • Decoder: decodes packets into PCM audio or video frames

  • Output: - Video: deliver decoded frames via video.decode_complete_cb for display - Audio: deliver decoded audio via audio.decode_complete_cb for audio output

Upper layer must provide buffer allocation/free callbacks for different pipeline stages.

6. Engine API flow

Typical Engine API flow:

  1. Fill bk_video_player_config_t: - audio/video pipeline buffer counts - audio/video buffer alloc/free callbacks - decode complete callbacks - optional: volume/mute control callbacks, playback finished callback, etc.

  2. bk_video_player_engine_new()

  3. Register parser/decoder: bk_video_player_engine_register_*() - This must be done before play. Otherwise there is no available container parser/decoder inside the player, and it cannot parse media or start playback. - Media probing (e.g. get_media_info / CLI info) also depends on registered container parsers. Without parsers, the player cannot probe or parse the file.

  4. bk_video_player_engine_open()

  5. bk_video_player_engine_set_file_path()

  6. bk_video_player_engine_play()

  7. Control with stop/pause/seek/ff/rewind as needed

  8. bk_video_player_engine_close()

  9. bk_video_player_engine_delete()

Important

  • bk_video_player_engine_set_volume() requires audio_set_volume_cb, otherwise it returns an unsupported error.

  • The playback finished callback is invoked asynchronously. Do not block for a long time inside it.

7. Playlist API flow

Playlist adds file list management and play mode:

  1. bk_video_player_playlist_new()

  2. bk_video_player_playlist_open()

  3. Add files via bk_video_player_playlist_add_file()

  4. Control playback via bk_video_player_playlist_play_file() / play_next() / play_prev() / etc.

  5. Configure play mode via bk_video_player_playlist_set_play_mode() (stop/repeat/loop)

  6. bk_video_player_playlist_close() + bk_video_player_playlist_delete()

8. Sample project

Project path:

  • projects/video_player_example

The project provides video_play_engine and video_play_playlist CLIs to validate the player pipeline.

9. Usage example (Engine)

The following example shows the basic Engine call sequence. In real projects, you typically integrate display and audio output modules in the callbacks.

#include "components/bk_video_player/bk_video_player_engine.h"
#include "bk_video_player_mp4_parser.h"
#include "bk_video_player_avi_parser.h"
#include "bk_video_player_hw_jpeg_decoder.h"
#include "bk_video_player_sw_jpeg_decoder.h"
#include "bk_video_player_aac_decoder.h"

static avdk_err_t audio_buf_alloc(void *user_data, video_player_buffer_t *buffer)
{
    (void)user_data;
    if (buffer == NULL) {
        return AVDK_ERR_INVALID_PARAM;
    }
    buffer->data = os_malloc(buffer->length);
    if (buffer->data == NULL) {
        return AVDK_ERR_NO_MEMORY;
    }
    return AVDK_ERR_OK;
}

static void audio_buf_free(void *user_data, video_player_buffer_t *buffer)
{
    (void)user_data;
    if (buffer && buffer->data) {
        os_free(buffer->data);
        buffer->data = NULL;
    }
}

static avdk_err_t video_buf_alloc(void *user_data, video_player_buffer_t *buffer)
{
    (void)user_data;
    if (buffer == NULL) {
        return AVDK_ERR_INVALID_PARAM;
    }
    buffer->data = os_malloc(buffer->length);
    if (buffer->data == NULL) {
        return AVDK_ERR_NO_MEMORY;
    }
    return AVDK_ERR_OK;
}

static void video_buf_free(void *user_data, video_player_buffer_t *buffer)
{
    (void)user_data;
    if (buffer && buffer->data) {
        os_free(buffer->data);
        buffer->data = NULL;
    }
}

static void on_audio_decoded(void *user_data, const video_player_audio_packet_meta_t *meta, video_player_buffer_t *buffer)
{
    (void)user_data;
    (void)meta;
    // Send decoded PCM to audio output, then free the buffer.
    audio_buf_free(NULL, buffer);
}

static void on_video_decoded(void *user_data, const video_player_video_frame_meta_t *meta, video_player_buffer_t *buffer)
{
    (void)user_data;
    (void)meta;
    // Display the decoded frame, then free the buffer.
    video_buf_free(NULL, buffer);
}

avdk_err_t video_file_playback_example(void)
{
    bk_video_player_engine_handle_t engine = NULL;
    bk_video_player_config_t cfg = {0};
    avdk_err_t ret = AVDK_ERR_OK;

    cfg.user_data = NULL;

    cfg.audio.parser_to_decode_buffer_count = 4;
    cfg.audio.decode_to_output_buffer_count = 4;
    cfg.audio.buffer_alloc_cb = audio_buf_alloc;
    cfg.audio.buffer_free_cb = audio_buf_free;
    cfg.audio.decode_complete_cb = on_audio_decoded;

    cfg.video.parser_to_decode_buffer_count = 4;
    cfg.video.decode_to_output_buffer_count = 4;
    cfg.video.buffer_alloc_cb = video_buf_alloc;
    cfg.video.buffer_free_cb = video_buf_free;
    cfg.video.decode_complete_cb = on_video_decoded;
    cfg.video.output_format = PIXEL_FMT_YUYV;

    ret = bk_video_player_engine_new(&engine, &cfg);
    if (ret != AVDK_ERR_OK) {
        return ret;
    }

    // Register parsers/decoders before media probing (info/get_media_info) or playback.
#if CONFIG_BK_VIDEO_PLAYER_ENABLE_MP4_PARSER
    ret = bk_video_player_engine_register_container_parser(engine, bk_video_player_get_mp4_parser_ops());
    if (ret != AVDK_ERR_OK) {
        bk_video_player_engine_delete(engine);
        return ret;
    }
#endif
#if CONFIG_BK_VIDEO_PLAYER_ENABLE_AVI_PARSER
    ret = bk_video_player_engine_register_container_parser(engine, bk_video_player_get_avi_parser_ops());
    if (ret != AVDK_ERR_OK) {
        bk_video_player_engine_delete(engine);
        return ret;
    }
#endif
#if CONFIG_BK_VIDEO_PLAYER_ENABLE_HW_JPEG_DECODER
    ret = bk_video_player_engine_register_video_decoder(engine, bk_video_player_get_hw_jpeg_decoder_ops());
    if (ret != AVDK_ERR_OK) {
        bk_video_player_engine_delete(engine);
        return ret;
    }
#endif
#if CONFIG_BK_VIDEO_PLAYER_ENABLE_SW_JPEG_DECODER
    ret = bk_video_player_engine_register_video_decoder(engine, bk_video_player_get_sw_jpeg_decoder_ops());
    if (ret != AVDK_ERR_OK) {
        bk_video_player_engine_delete(engine);
        return ret;
    }
#endif
#if CONFIG_BK_VIDEO_PLAYER_ENABLE_AAC_DECODER
    ret = bk_video_player_engine_register_audio_decoder(engine, bk_video_player_get_aac_audio_decoder_ops());
    if (ret != AVDK_ERR_OK) {
        bk_video_player_engine_delete(engine);
        return ret;
    }
#endif

    ret = bk_video_player_engine_open(engine);
    if (ret != AVDK_ERR_OK) {
        bk_video_player_engine_delete(engine);
        return ret;
    }

    ret = bk_video_player_engine_set_file_path(engine, "/sd0/record.mp4");
    if (ret == AVDK_ERR_OK) {
        ret = bk_video_player_engine_play(engine);
    }

    // Stop playback when needed.
    if (ret == AVDK_ERR_OK) {
        (void)bk_video_player_engine_stop(engine);
    }

    (void)bk_video_player_engine_close(engine);
    (void)bk_video_player_engine_delete(engine);
    return ret;
}