static int decode_and_send_const(DNxHDDecodeStreamConnect* connect, const unsigned char* buffer,
    unsigned int bufferSize)
{
    int finished;

    /* We know that avcodec_decode_video will not modify the input data, so we can cast buffer to non-const */
    avcodec_decode_video(connect->decoder->dec, connect->decoder->decFrame, &finished, (unsigned char*)buffer, bufferSize);
    if (!finished)
    {
        ml_log_error("Failed to decode DNxHD video\n");
        return 0;
    }

    /* reformat decoded frame */
    yuv422_to_yuv422(connect->streamInfo.width, connect->streamInfo.height, 0,
        connect->decoder->decFrame, connect->sinkBuffer);

    /* send decoded frame to sink */
    if (!msk_receive_stream_frame(connect->sink, connect->sinkStreamId, connect->sinkBuffer,
        connect->sinkBufferSize))
    {
        ml_log_error("failed to write frame to media sink\n");
        return 0;
    }

    return 1;
}
Example #2
0
ReadWriteLockGuard::ReadWriteLockGuard(pthread_rwlock_t* rwlock, bool writeLock)
    : _rwlock(NULL)
{
    if (writeLock)
    {
        if (pthread_rwlock_wrlock(rwlock) != 0)
        {
            ml_log_error("pthread_rwlock_wrlock failed\n");
        }
        else
        {
            _rwlock = rwlock;
        }
    }
    else
    {
        if (pthread_rwlock_rdlock(rwlock) != 0)
        {
            ml_log_error("pthread_rwlock_rdlock failed\n");
        }
        else
        {
            _rwlock = rwlock;
        }
    }
}
Example #3
0
static int ddc_allocate_buffer(void* data, int streamId, unsigned char** buffer, unsigned int bufferSize)
{
    DVDecodeStreamConnect* connect = (DVDecodeStreamConnect*)data;
    int result;

    if (connect->sourceStreamId != streamId)
    {
        ml_log_error("Buffer allocation request for unknown source stream %d in copy connect\n", streamId);
        return 0;
    }

    if (connect->dvDataSize != bufferSize)
    {
        ml_log_error("Invalid DV buffer allocation request for stream %d in copy connect\n", streamId);
        return 0;
    }

    /* ask sink to allocate buffer for decoded frame */
    result = msk_get_stream_buffer(connect->sink, connect->sinkStreamId, connect->sinkBufferSize,
        &connect->sinkBuffer);
    if (!result)
    {
        ml_log_error("Sink failed to allocate buffer for stream %d for DV decoder connector\n", streamId);
        return 0;
    }

    *buffer = connect->dvData;
    return 1;
}
static int create_dnxhd_decoder(StreamFormat format, int width, int height, int numFFMPEGThreads, DNxHDDecoder** decoder)
{
    DNxHDDecoder* newDecoder = NULL;
    AVCodec* avDecoder = NULL;


    CALLOC_ORET(newDecoder, DNxHDDecoder, 1);

    newDecoder->format = format;
    newDecoder->width = width;
    newDecoder->height = height;


    avDecoder = avcodec_find_decoder(CODEC_ID_DNXHD);
    if (!avDecoder)
    {
        ml_log_error("Could not find the DNxHD decoder\n");
        goto fail;
    }

    newDecoder->dec = avcodec_alloc_context();
    if (!newDecoder->dec)
    {
        ml_log_error("Could not allocate DNxHD decoder context\n");
        goto fail;
    }

    if (numFFMPEGThreads > 1)
    {
        avcodec_thread_init(newDecoder->dec, numFFMPEGThreads);
        newDecoder->isThreaded = 1;
    }


    avcodec_set_dimensions(newDecoder->dec, width, height);
    newDecoder->dec->pix_fmt = PIX_FMT_YUV422P;

    if (avcodec_open(newDecoder->dec, avDecoder) < 0)
    {
        ml_log_error("Could not open decoder\n");
        goto fail;
    }
    newDecoder->openedDecoder = 1;

    newDecoder->decFrame = avcodec_alloc_frame();
    if (!newDecoder->decFrame)
    {
        ml_log_error("Could not allocate decoded frame\n");
        goto fail;
    }

    *decoder = newDecoder;
    return 1;

fail:
    free_dnxhd_decoder(&newDecoder);
    return 0;
}
Example #5
0
static int ddc_receive_frame(void* data, int streamId, unsigned char* buffer, unsigned int bufferSize)
{
    DVDecodeStreamConnect* connect = (DVDecodeStreamConnect*)data;
    int status;
    int result = 1;

    if (connect->sourceStreamId != streamId)
    {
        ml_log_error("Received frame for unknown source stream %d in copy connect\n", streamId);
        return 0;
    }

    /* signal to ddc_sync at later time that we have received a frame to decode and send */
    connect->frameWasReceived = 1;


    if (!connect->useWorkerThread)
    {
        result = decode_and_send(connect);
    }
    else
    {

        /* check that the worker isn't busy */

        PTHREAD_MUTEX_LOCK(&connect->workerMutex);
        if (connect->workerIsBusy)
        {
            ml_log_error("DV connect worker thread is still busy, and therefore cannot receive a new frame\n");
            result = 0;
        }
        PTHREAD_MUTEX_UNLOCK(&connect->workerMutex);

        if (result != 1)
        {
            return result;
        }


        /* signal worker that a new frame is ready */

        PTHREAD_MUTEX_LOCK(&connect->workerMutex);
        connect->frameIsReady = 1;
        status = pthread_cond_signal(&connect->frameIsReadyCond);
        if (status != 0)
        {
            ml_log_error("DV connect worker thread failed to send frame is ready condition signal\n");
            result = 0;
        }
        PTHREAD_MUTEX_UNLOCK(&connect->workerMutex);
    }

    return result;
}
Example #6
0
int vsd_dump(const char* filename, FILE* output)
{
    VideoSwitchDatabase* db;
    unsigned char buf[VIDEO_SWITCH_DB_ENTRY_SIZE * 50];
    int numEntries = 0;
    int startEntry = 0;

    if (!vsd_open_read(filename, &db))
    {
        return 0;
    }


    do
    {
        if (!vsd_load(db, startEntry, buf, VIDEO_SWITCH_DB_ENTRY_SIZE * 50, &numEntries))
        {
            ml_log_error("Failed to load entries from video switch database\n");
            goto fail;
        }

        int i;
        for (i = 0; i < numEntries; i++)
        {
            VideoSwitchDbEntry entry;
            if (!vsd_parse_entry(&buf[VIDEO_SWITCH_DB_ENTRY_SIZE * i],
                VIDEO_SWITCH_DB_ENTRY_SIZE * (50 - i), &entry))
            {
                ml_log_error("Failed to parse video switch database entry %d\n", i);
                goto fail;
            }

            printf("%d, %s, %04d-%02d-%02d, %02d:%02d:%02d:%02d%c\n",
                entry.sourceIndex, entry.sourceId, entry.year, entry.month, entry.day,
                entry.tc.hour, entry.tc.min, entry.tc.sec, entry.tc.frame, entry.tc.isDropFrame ? 'D' : ' ');
        }

        startEntry += numEntries;

    } while (numEntries > 0);

    vsd_close(&db);
    return 1;

fail:
    vsd_close(&db);
    return 0;
}
static int ddc_allocate_buffer(void* data, int streamId, unsigned char** buffer, unsigned int bufferSize)
{
    DNxHDDecodeStreamConnect* connect = (DNxHDDecodeStreamConnect*)data;
    int result;

    if (connect->sourceStreamId != streamId)
    {
        ml_log_error("Buffer allocation request for unknown source stream %d in copy connect\n", streamId);
        return 0;
    }

    if (connect->dnxhdDataSize < bufferSize)
    {
        /* allocate buffer if neccessary and set size */
        if (connect->dnxhdDataAllocSize < bufferSize)
        {
            SAFE_FREE(&connect->dnxhdData);
            connect->dnxhdDataSize = 0;
            connect->dnxhdDataAllocSize = 0;

            CALLOC_ORET(connect->dnxhdData, unsigned char,
                bufferSize + FF_INPUT_BUFFER_PADDING_SIZE /* FFMPEG for some reason needs the extra space */);
            connect->dnxhdDataAllocSize = bufferSize; /* we lie and don't include the FFMPEG extra space */
        }
        connect->dnxhdDataSize = bufferSize;
    }
Example #8
0
int vsd_load(VideoSwitchDatabase* db, int startEntry, unsigned char* buffer, int bufferSize, int* numEntries)
{
    int totalEntries = vsd_get_num_entries(db);
    if (totalEntries == 0)
    {
        *numEntries = 0;
        return 1;
    }

    int readEntries = totalEntries - startEntry;
    readEntries = (bufferSize / VIDEO_SWITCH_DB_ENTRY_SIZE < readEntries) ?
        bufferSize / VIDEO_SWITCH_DB_ENTRY_SIZE : readEntries;
    if (readEntries <= 0)
    {
        *numEntries = 0;
        return 1;
    }

    if (fseeko(db->file, startEntry * VIDEO_SWITCH_DB_ENTRY_SIZE, SEEK_SET) != 0)
    {
        ml_log_error("Failed to seek to position in video switch database file: %s\n", strerror(errno));
        return 0;
    }

    *numEntries = fread(buffer, VIDEO_SWITCH_DB_ENTRY_SIZE, readEntries, db->file);
    return 1;
}
Example #9
0
int msc_add_stream_to_map(MediaSourceStreamMap* map, int streamId, int sourceId)
{
    int i;

    for (i = 0; i < map->numStreams; i++)
    {
        if (map->streams[i].streamId == streamId)
        {
            map->streams[i].sourceId = sourceId;
            return 1;
        }
    }

    if (map->numStreams + 1 < (int)(sizeof(map->streams) / sizeof(int)))
    {
        map->streams[map->numStreams].sourceId = sourceId;
        map->streams[map->numStreams].streamId = streamId;
        map->numStreams++;
    }
    else
    {
        ml_log_error("Number streams exceeds maximum (%d) expected\n", sizeof(map->streams) / sizeof(int));
        return 0;
    }

    return 1;
}
Example #10
0
ReadWriteLockGuard::~ReadWriteLockGuard()
{
    if (_rwlock != NULL)
    {
        if (pthread_rwlock_unlock(_rwlock) != 0)
        {
            ml_log_error("pthread_rwlock_unlock failed\n");
        }
    }
}
Example #11
0
static int cyc_receive_frame_const(void* data, int streamId, const unsigned char* buffer, unsigned int bufferSize)
{
    CopyStreamConnect* connect = (CopyStreamConnect*)data;

    if (connect->sourceStreamId != streamId)
    {
        ml_log_error("Received frame for unknown source stream %d in copy connect\n", streamId);
        return 0;
    }

    if (!msk_receive_stream_frame_const(connect->sink, connect->sinkStreamId, buffer, bufferSize))
    {
        ml_log_error("failed to write frame to media sink\n");
        return 0;
    }

    return 1;

}
Example #12
0
File: utils.c Project: dluobo/ingex
int init_cond_var(pthread_cond_t* cond)
{
    int err;

    if ((err = pthread_cond_init(cond, NULL)) != 0)
    {
        ml_log_error("Failed to initialise conditional variable: %s\n", strerror(err));
        return 0;
    }
    return 1;
}
Example #13
0
File: utils.c Project: dluobo/ingex
int init_mutex(pthread_mutex_t* mutex)
{
    int err;

    if ((err = pthread_mutex_init(mutex, NULL)) != 0)
    {
        ml_log_error("Failed to initialise mutex: %s\n", strerror(err));
        return 0;
    }
    return 1;
}
Example #14
0
int vsd_open_write(const char* filename, VideoSwitchDatabase** db)
{
    FILE* file = fopen(filename, "wb");
    if (file == NULL)
    {
        ml_log_error("Failed to open video switch database file '%s': %s\n", filename, strerror(errno));
        return 0;
    }

    return open(file, db);
}
Example #15
0
int vsd_append_entry_with_date(VideoSwitchDatabase* db, int sourceIndex, const char* sourceId,  int year, int month, int day, const Timecode* tc)
{
    if (fseeko(db->file, 0, SEEK_END) != 0)
    {
        ml_log_error("Failed to seek to end of video switch database file: %s\n", strerror(errno));
        return 0;
    }

    char buf[VIDEO_SWITCH_DB_ENTRY_SIZE];
    memset(buf, 0, VIDEO_SWITCH_DB_ENTRY_SIZE);

    /* source index - 1 byte */
    buf[SOURCE_INDEX_OFFSET] = (unsigned char)(sourceIndex);

    /* source id - string plus null terminator */
    strncpy(&buf[SOURCE_ID_OFFSET], sourceId, SOURCE_ID_LEN - 1);

    /* date */
    snprintf(&buf[DATE_OFFSET], DATE_LEN + 1, "%04d-%02d-%02d",
        (year > 9999) ? 0 : year,
        (month > 12) ? 0 : month,
        (day > 31) ? 0 : day);

    /* timecode - text timecode plus drop frame indicator */
    snprintf(&buf[TIMECODE_OFFSET], TIMECODE_LEN + 1, "%02d:%02d:%02d:%02d%c",
        (tc->hour > 24) ? 0 : tc->hour,
        (tc->min > 59) ? 0 : tc->min,
        (tc->sec > 59) ? 0 : tc->sec,
        (tc->frame > 30) ? 0 : tc->frame,
        tc->isDropFrame ? 'D' : 'N');


    if (fwrite(buf, VIDEO_SWITCH_DB_ENTRY_SIZE, 1, db->file) != 1)
    {
        ml_log_error("Failed to write video switch database entry: %s\n", strerror(errno));
        return 0;
    }
    fflush(db->file);

    return 1;
}
Example #16
0
int vsd_get_num_entries(VideoSwitchDatabase* db)
{
    struct stat st;

    if (fstat(fileno(db->file), &st) != 0)
    {
        ml_log_error("Failed to stat video switch database file: %s\n", strerror(errno));
        return 0;
    }

    return st.st_size / VIDEO_SWITCH_DB_ENTRY_SIZE;
}
Example #17
0
static int cyc_allocate_buffer(void* data, int streamId, unsigned char** buffer, unsigned int bufferSize)
{
    CopyStreamConnect* connect = (CopyStreamConnect*)data;

    if (connect->sourceStreamId != streamId)
    {
        ml_log_error("Buffer allocation request for unknown source stream %d in copy connect\n", streamId);
        return 0;
    }

    return msk_get_stream_buffer(connect->sink, connect->sinkStreamId, bufferSize, buffer);
}
Example #18
0
static int bmsrc_accept_frame(void* data, int streamId, const FrameInfo* frameInfo)
{
    BufferedMediaSource* bufSource = (BufferedMediaSource*)data;
    BufferedStream* stream = get_stream(bufSource, streamId);

    if (stream == NULL)
    {
        ml_log_error("Unknown stream %d\n", streamId);
        return 0;
    }

    return !stream->isDisabled;
}
Example #19
0
static int ddc_sync(void* data)
{
    DVDecodeStreamConnect* connect = (DVDecodeStreamConnect*)data;
    int status;
    int workerResult = 0;
    int doneWaiting;

    if (!connect->frameWasReceived)
    {
        /* no work was required */
        return 1;
    }

    /* reset for next time */
    connect->frameWasReceived = 0;

    if (!connect->useWorkerThread)
    {
        /* work is already complete */
        return 1;
    }

    /* TODO: timed wait to prevent eternal loop? */

    /* wait until worker has processed the frame and is no longer busy */
    doneWaiting = 0;
    while (!doneWaiting && !connect->stopped)
    {
        /* wait for worker */
        PTHREAD_MUTEX_LOCK(&connect->workerMutex);
        if (connect->workerIsBusy)
        {
            status = pthread_cond_wait(&connect->workerIsBusyCond, &connect->workerMutex);
            if (status != 0)
            {
                ml_log_error("DV connect worker thread failed to wait for condition\n");
                /* TODO: don't try again? */
            }
        }

        /* worker is not busy and no frame is waiting to be processed */
        if (!connect->workerIsBusy && !connect->frameIsReady)
        {
            workerResult = connect->workerResult;
            doneWaiting = 1;
        }
        PTHREAD_MUTEX_UNLOCK(&connect->workerMutex);
    }

    return workerResult;
}
Example #20
0
static int init_frame(X11DisplayFrame* frame)
{
    X11DisplaySink* sink = (X11DisplaySink*)frame->sink;

    XLockDisplay(sink->x11Common.windowInfo.display);
    sink->depth = DefaultDepth(sink->x11Common.windowInfo.display, DefaultScreen(sink->x11Common.windowInfo.display));
    sink->visual = DefaultVisual(sink->x11Common.windowInfo.display, DefaultScreen(sink->x11Common.windowInfo.display));
    XUnlockDisplay(sink->x11Common.windowInfo.display);

    if (sink->depth < 15)
    {
        ml_log_error("Unknown display depth %d\n", sink->depth);
        return 0;
    }

    frame->videoFormat = sink->videoFormat;

    if (sink->videoFormat == UYVY_10BIT_FORMAT)
    {
        frame->inputBufferSize = (sink->inputWidth + 5) / 6 * 16 * sink->inputHeight;
        frame->convertBufferSize = sink->inputWidth * sink->inputHeight * 2;
        if (sink->swScale != 1)
        {
            frame->scaleBufferSize = sink->width * sink->height * 2;
        }
    }
    else if (frame->videoFormat == UYVY_FORMAT ||
        frame->videoFormat == YUV422_FORMAT)
    {
        frame->inputBufferSize = sink->inputWidth * sink->inputHeight * 2;
        if (sink->swScale != 1)
        {
            frame->scaleBufferSize = sink->width * sink->height * 2;
        }
    }
    else /* YUV420_FORMAT */
    {
        frame->inputBufferSize = sink->inputWidth * sink->inputHeight * 3 / 2;
        if (sink->swScale != 1)
        {
            frame->scaleBufferSize = sink->width * sink->height * 3 / 2;
        }
    }
    frame->rgbBufferSize = sink->width * sink->height * 4; /* max 32-bit */


    MALLOC_ORET(frame->inputBuffer, unsigned char, frame->inputBufferSize);
    if (frame->convertBufferSize > 0)
    {
        MALLOC_ORET(frame->convertBuffer, unsigned char, frame->convertBufferSize);
    }
Example #21
0
int vsd_parse_entry(const unsigned char* entryBuffer, int entryBufferSize, VideoSwitchDbEntry* entry)
{
    int hour, min, sec, frame;
    char isDropFrame;
    int year, month, day;

    if (entryBufferSize < VIDEO_SWITCH_DB_ENTRY_SIZE)
    {
        ml_log_error("Entry buffer size %d is smaller than the entry size %d\n", entryBufferSize, VIDEO_SWITCH_DB_ENTRY_SIZE);
        return 0;
    }

    if (sscanf((const char*)&entryBuffer[DATE_OFFSET], "%04d-%02d-%02d", &year, &month, &day) != 3)
    {
        ml_log_error("Failed to parse date in video switch database entry\n");
        return 0;
    }

    if (sscanf((const char*)&entryBuffer[TIMECODE_OFFSET], "%02d:%02d:%02d:%02d%c", &hour, &min, &sec, &frame, &isDropFrame) != 5)
    {
        ml_log_error("Failed to parse timecode in video switch database entry\n");
        return 0;
    }

    entry->sourceIndex = (int)entryBuffer[SOURCE_INDEX_OFFSET];
    entry->sourceId = (const char*)(&entryBuffer[SOURCE_ID_OFFSET]);
    entry->year = year;
    entry->month = month;
    entry->day = day;
    entry->tc.hour = hour;
    entry->tc.min = min;
    entry->tc.sec = sec;
    entry->tc.frame = frame;
    entry->tc.isDropFrame = (isDropFrame == 'D');

    return 1;
}
Example #22
0
int bks_create(const StreamInfo* videoStreamInfo, int64_t length, MediaSource** source)
{
    BlankSource* newSource = NULL;

    if (videoStreamInfo->type != PICTURE_STREAM_TYPE)
    {
        ml_log_error("Blank source only does video\n");
        return 0;
    }


    CALLOC_ORET(newSource, BlankSource, 1);

    newSource->length = length;

    newSource->mediaSource.data = newSource;
    newSource->mediaSource.finalise_blank_source = bks_finalise_blank_source;
    newSource->mediaSource.get_num_streams = bks_get_num_streams;
    newSource->mediaSource.get_stream_info = bks_get_stream_info;
    newSource->mediaSource.set_frame_rate_or_disable = bks_set_frame_rate_or_disable;
    newSource->mediaSource.disable_stream = bks_disable_stream;
    newSource->mediaSource.disable_video = bks_disable_video;
    newSource->mediaSource.stream_is_disabled = bks_stream_is_disabled;
    newSource->mediaSource.read_frame = bks_read_frame;
    newSource->mediaSource.is_seekable = bks_is_seekable;
    newSource->mediaSource.seek = bks_seek;
    newSource->mediaSource.get_length = bks_get_length;
    newSource->mediaSource.get_position = bks_get_position;
    newSource->mediaSource.get_available_length = bks_get_available_length;
    newSource->mediaSource.eof = bks_eof;
    newSource->mediaSource.set_source_name = bks_set_source_name;
    newSource->mediaSource.set_clip_id = bks_set_clip_id;
    newSource->mediaSource.close = bks_close;

    newSource->streamInfo = *videoStreamInfo;
    newSource->streamInfo.sourceId = msc_create_id();

    CHK_OFAIL(add_known_source_info(&newSource->streamInfo, SRC_INFO_TITLE, "Blank Source"));
    CHK_OFAIL(add_known_source_info(&newSource->streamInfo, SRC_INFO_ORIGINAL_STREAM_FORMAT,
                                    get_stream_format_string(newSource->streamInfo.format)));


    *source = &newSource->mediaSource;
    return 1;

fail:
    bks_close(newSource);
    return 0;
}
Example #23
0
static int bmsrc_allocate_buffer(void* data, int streamId, unsigned char** buffer, unsigned int bufferSize)
{
    BufferedMediaSource* bufSource = (BufferedMediaSource*)data;
    BufferedStream* stream = get_stream(bufSource, streamId);

    if (stream == NULL)
    {
        ml_log_error("Unknown stream %d\n", streamId);
        return 0;
    }

    if (bufferSize > stream->bufferSize)
    {
        MALLOC_ORET(stream->buffer, unsigned char, bufferSize);
        stream->bufferSize = bufferSize;
    }
Example #24
0
static int append_source(MediaSourceList* sourceList, MediaSource** source)
{
    MediaSourceElement* ele = sourceList;
    MediaSourceElement* newEle = NULL;
    int i;

    /* handle first appended source */
    if (ele->source == NULL)
    {
        ele->source = *source;
        ele->numStreams = msc_get_num_streams(*source);
        *source = NULL;
        return 1;
    }

    /* move to end */
    while (ele->next != NULL)
    {
        ele = ele->next;
    }

    /* create element */
    if ((newEle = (MediaSourceElement*)malloc(sizeof(MediaSourceElement))) == NULL)
    {
        ml_log_error("Failed to allocate memory\n");
        return 0;
    }
    memset(newEle, 0, sizeof(MediaSourceElement));

    /* append source and take ownership */
    ele->next = newEle;
    newEle->source = *source;

    /* get num streams and disabled count */
    newEle->numStreams = msc_get_num_streams(*source);
    newEle->disabledStreamCount = 0;
    for (i = 0; i < newEle->numStreams; i++)
    {
        if (msc_stream_is_disabled(newEle->source, i))
        {
            newEle->disabledStreamCount++;
        }
    }

    *source = NULL;
    return 1;
}
Example #25
0
File: utils.c Project: dluobo/ingex
int create_joinable_thread(pthread_t* thread, void* (*start_func)(void*), void* arg)
{
    int result;
    pthread_attr_t attr;
    pthread_t newThread;

    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

    result = pthread_create(&newThread, &attr, start_func, arg);
    if (result == 0)
    {
        *thread = newThread;
    }
    else
    {
        ml_log_error("Failed to create joinable thread: %s\n", strerror(result));
    }

    pthread_attr_destroy(&attr);

    return result == 0;
}
Example #26
0
int create_dv_connect(MediaSink* sink, int sinkStreamId, int sourceStreamId,
    const StreamInfo* streamInfo, int numFFMPEGThreads, int useWorkerThread, StreamConnect** connect)
{
    DVDecodeStreamConnect* newConnect;
    StreamInfo decodedStreamInfo;
    int result;

    /* register stream with sink */
    if (streamInfo->format == DV25_YUV420_FORMAT)
    {
        decodedStreamInfo = *streamInfo;
        decodedStreamInfo.format = YUV420_FORMAT;

        result = msk_accept_stream(sink, &decodedStreamInfo);
    }
    else if (streamInfo->format == DV25_YUV411_FORMAT)
    {
        decodedStreamInfo = *streamInfo;
        decodedStreamInfo.format = YUV411_FORMAT;

        result = msk_accept_stream(sink, &decodedStreamInfo);
    }
    else /* streamInfo->format == DV50_FORMAT || streamInfo->format == DV100_FORMAT */
    {
        decodedStreamInfo = *streamInfo;
        decodedStreamInfo.format = YUV422_FORMAT;

        result = msk_accept_stream(sink, &decodedStreamInfo);
    }

    /* try UYVY if default format is not accepted */
    if (!result)
    {
        decodedStreamInfo = *streamInfo;
        decodedStreamInfo.format = UYVY_FORMAT;

        result = msk_accept_stream(sink, &decodedStreamInfo);
    }

    if (!result)
    {
        /* shouldn't be here because a call to dv_connect_accept() should've returned false already */
        ml_log_error("Failed to create DV connector because format is not accepted\n");
        return 0;
    }


    if (!msk_register_stream(sink, sinkStreamId, &decodedStreamInfo))
    {
        /* could have failed if max streams exceeded for example */
        return 0;
    }


    CALLOC_ORET(newConnect, DVDecodeStreamConnect, 1);

    newConnect->useWorkerThread = useWorkerThread;
    newConnect->decodedFormat = decodedStreamInfo.format;

    if (streamInfo->format == DV25_YUV420_FORMAT || streamInfo->format == DV25_YUV411_FORMAT)
    {
        newConnect->dvDataSize = (stream_is_pal_frame_rate(streamInfo) ? 144000 : 120000);
    }
    else if (streamInfo->format == DV50_FORMAT)
    {
        newConnect->dvDataSize = (stream_is_pal_frame_rate(streamInfo) ? 288000 : 240000);
    }
    else /* streamInfo->format == DV100_FORMAT */
    {
        newConnect->dvDataSize = 576000;
    }
    if ((newConnect->dvData = (unsigned char*)calloc(
        newConnect->dvDataSize + FF_INPUT_BUFFER_PADDING_SIZE /* FFMPEG for some reason needs the extra space */,
        sizeof(unsigned char))) == NULL)
    {
        ml_log_error("Failed to allocate memory\n");
        goto fail;
    }

    newConnect->sink = sink;
    newConnect->sourceStreamId = sourceStreamId;
    newConnect->sinkStreamId = sinkStreamId;
    newConnect->streamInfo = *streamInfo;
    if (decodedStreamInfo.format == UYVY_FORMAT)
    {
        newConnect->sinkBufferSize = streamInfo->width * streamInfo->height * 2;
    }
    else if (decodedStreamInfo.format == YUV422_FORMAT)
    {
        newConnect->sinkBufferSize = streamInfo->width * streamInfo->height * 2;
    }
    else /* YUV420 / YUV411 */
    {
        newConnect->sinkBufferSize = streamInfo->width * streamInfo->height * 3 / 2;
    }

    newConnect->streamConnect.data = newConnect;
    newConnect->streamConnect.get_source_listener = ddc_get_source_listener;
    newConnect->streamConnect.sync = ddc_sync;
    newConnect->streamConnect.close = ddc_close;

    newConnect->sourceListener.data = newConnect;
    newConnect->sourceListener.accept_frame = ddc_accept_frame;
    newConnect->sourceListener.allocate_buffer = ddc_allocate_buffer;
    newConnect->sourceListener.deallocate_buffer = ddc_deallocate_buffer;
    newConnect->sourceListener.receive_frame = ddc_receive_frame;
    newConnect->sourceListener.receive_frame_const = ddc_receive_frame_const;



    /* create DV decoder */

    CHK_OFAIL(init_dv_decoder_resources());

    CHK_OFAIL(create_dv_decoder(streamInfo->format, streamInfo->width, streamInfo->height,
        numFFMPEGThreads, &newConnect->decoder));


    /* create worker thread */

    if (useWorkerThread)
    {
        CHK_OFAIL(init_mutex(&newConnect->workerMutex));
        CHK_OFAIL(init_cond_var(&newConnect->frameIsReadyCond));
        CHK_OFAIL(init_cond_var(&newConnect->workerIsBusyCond));

        CHK_OFAIL(create_joinable_thread(&newConnect->workerThreadId, worker_thread, newConnect));
    }


    *connect = &newConnect->streamConnect;
    return 1;

fail:
    ddc_close(newConnect);
    return 0;
}
Example #27
0
static int ddc_receive_frame_const(void* data, int streamId, const unsigned char* buffer, unsigned int bufferSize)
{
    DVDecodeStreamConnect* connect = (DVDecodeStreamConnect*)data;
    int status;
    int result;
    unsigned char* nonconstBuffer;

    if (connect->useWorkerThread)
    {
        /* the worker thread requires the data to be copied into connect->dvData */
        result = ddc_allocate_buffer(data, streamId, &nonconstBuffer, bufferSize);
        if (result)
        {
            memcpy(nonconstBuffer, buffer, bufferSize);
            result = ddc_receive_frame(data, streamId, nonconstBuffer, bufferSize);
        }
        return result;
    }


    if (connect->sourceStreamId != streamId)
    {
        ml_log_error("Received frame for unknown source stream %d in copy connect\n", streamId);
        return 0;
    }

    /* ask sink to allocate buffer for decoded frame */
    result = msk_get_stream_buffer(connect->sink, connect->sinkStreamId, connect->sinkBufferSize,
        &connect->sinkBuffer);
    if (!result)
    {
        ml_log_error("Sink failed to allocate buffer for stream %d for DV decoder connector\n", streamId);
        return 0;
    }


    /* signal to ddc_sync at later time that we have received a frame to decode and send */
    connect->frameWasReceived = 1;


    if (!connect->useWorkerThread)
    {
        result = decode_and_send_const(connect, buffer, bufferSize);
    }
    else
    {

        /* check that the worker isn't busy */

        PTHREAD_MUTEX_LOCK(&connect->workerMutex);
        if (connect->workerIsBusy)
        {
            ml_log_error("DV connect worker thread is still busy, and therefore cannot receive a new frame\n");
            result = 0;
        }
        PTHREAD_MUTEX_UNLOCK(&connect->workerMutex);

        if (result != 1)
        {
            return result;
        }


        /* signal worker that a new frame is ready */

        PTHREAD_MUTEX_LOCK(&connect->workerMutex);
        connect->frameIsReady = 1;
        status = pthread_cond_signal(&connect->frameIsReadyCond);
        if (status != 0)
        {
            ml_log_error("DV connect worker thread failed to send frame is ready condition signal\n");
            result = 0;
        }
        PTHREAD_MUTEX_UNLOCK(&connect->workerMutex);
    }

    return result;
}
Example #28
0
static int decode_and_send_const(DVDecodeStreamConnect* connect, const unsigned char* buffer,
    unsigned int bufferSize)
{
    int finished;

    /* We know that avcodec_decode_video will not modify the input data, so we can cast buffer to non-const */
    avcodec_decode_video(connect->decoder->dec, connect->decoder->decFrame, &finished, (unsigned char*)buffer, bufferSize);
    if (!finished)
    {
        ml_log_error("error decoding DV video\n");
        return 0;
    }

    /* reformat decoded frame */
    if (connect->streamInfo.format == DV25_YUV420_FORMAT)
    {
        if (connect->decodedFormat == UYVY_FORMAT)
        {
            yuv4xx_to_uyvy(connect->streamInfo.width, connect->streamInfo.height, stream_is_pal_frame_rate(&connect->streamInfo),
                connect->decoder->decFrame, connect->sinkBuffer);
        }
        else /* YUV420 */
        {
            yuv4xx_to_yuv4xx(connect->streamInfo.width, connect->streamInfo.height, stream_is_pal_frame_rate(&connect->streamInfo),
                connect->decoder->decFrame, connect->sinkBuffer);
        }
    }
    else if (connect->streamInfo.format == DV25_YUV411_FORMAT)
    {
        if (connect->decodedFormat == UYVY_FORMAT)
        {
            yuv4xx_to_uyvy(connect->streamInfo.width, connect->streamInfo.height, stream_is_pal_frame_rate(&connect->streamInfo),
                connect->decoder->decFrame, connect->sinkBuffer);
        }
        else /* YUV411 */
        {
            yuv4xx_to_yuv4xx(connect->streamInfo.width, connect->streamInfo.height, stream_is_pal_frame_rate(&connect->streamInfo),
                connect->decoder->decFrame, connect->sinkBuffer);
        }
    }
    else /* DV50_FORMAT or DV100_FORMAT */
    {
        if (connect->decodedFormat == UYVY_FORMAT)
        {
            yuv422_to_uyvy(connect->streamInfo.width, connect->streamInfo.height, stream_is_pal_frame_rate(&connect->streamInfo),
                connect->decoder->decFrame, connect->sinkBuffer);
        }
        else /* YUV422 */
        {
            yuv422_to_yuv422(connect->streamInfo.width, connect->streamInfo.height, stream_is_pal_frame_rate(&connect->streamInfo),
                connect->decoder->decFrame, connect->sinkBuffer);
        }
    }

    /* send decoded frame to sink */
    if (!msk_receive_stream_frame(connect->sink, connect->sinkStreamId, connect->sinkBuffer,
        connect->sinkBufferSize))
    {
        ml_log_error("failed to write frame to media sink\n");
        return 0;
    }

    return 1;
}
Example #29
0
static int create_dv_decoder(StreamFormat format, int width, int height, int numFFMPEGThreads, DVDecoder** decoder)
{
    int decoderResourceRefCount = g_decoderResourceRefCount;
    int i;
    DVDecoder* newDecoder = NULL;
    int numDecoders = g_decoderResource.numDecoders;
    AVCodec* avDecoder = NULL;

    /* see if there is matching decoder not in use */
    if (decoderResourceRefCount > 0)
    {
        for (i = 0; i < numDecoders; i++)
        {
            if (!g_decoderResource.decoder[i]->inUse &&
                g_decoderResource.decoder[i]->format == format &&
                g_decoderResource.decoder[i]->width == width &&
                g_decoderResource.decoder[i]->height == height)
            {
                /* found one not in use */
                *decoder = g_decoderResource.decoder[i];
                g_decoderResource.decoder[i]->inUse = 1;
                return 1;
            }
        }
    }


    /* create a new one */

    CALLOC_ORET(newDecoder, DVDecoder, 1);

    newDecoder->inUse = 1;
    newDecoder->format = format;
    newDecoder->width = width;
    newDecoder->height = height;


    avDecoder = avcodec_find_decoder(CODEC_ID_DVVIDEO);
    if (!avDecoder)
    {
        ml_log_error("Could not find the DV decoder\n");
        goto fail;
    }

    newDecoder->dec = avcodec_alloc_context();
    if (!newDecoder->dec)
    {
        ml_log_error("Could not allocate DV decoder context\n");
        goto fail;
    }

    if (numFFMPEGThreads > 1)
    {
        avcodec_thread_init(newDecoder->dec, numFFMPEGThreads);
        newDecoder->isThreaded = 1;
    }


    avcodec_set_dimensions(newDecoder->dec, width, height);
    if (format == DV25_YUV420_FORMAT)
    {
        newDecoder->dec->pix_fmt = PIX_FMT_YUV420P;
    }
    else if (format == DV25_YUV411_FORMAT)
    {
        newDecoder->dec->pix_fmt = PIX_FMT_YUV411P;
    }
    else
    {
        newDecoder->dec->pix_fmt = PIX_FMT_YUV422P;
    }

    if (avcodec_open(newDecoder->dec, avDecoder) < 0)
    {
        ml_log_error("Could not open decoder\n");
        goto fail;
    }
    newDecoder->openedDecoder = 1;

    newDecoder->decFrame = avcodec_alloc_frame();
    if (!newDecoder->decFrame)
    {
        ml_log_error("Could not allocate decoded frame\n");
        goto fail;
    }


    /* add to static resources if they have been initialised */

    if (decoderResourceRefCount > 0)
    {
        if ((size_t)g_decoderResource.numDecoders >= sizeof(g_decoderResource.decoder) / sizeof(DVDecoder*))
        {
            /* more than x decoders? what are you doing? */
            ml_log_error("Number of DV decoders exceeded hard coded limit %d\n",
                sizeof(g_decoderResource.decoder) / sizeof(DVDecoder));
            goto fail;
        }

        PTHREAD_MUTEX_LOCK(&g_decoderResource.resourceMutex);
        g_decoderResource.decoder[g_decoderResource.numDecoders] = newDecoder;
        g_decoderResource.numDecoders++;
        PTHREAD_MUTEX_UNLOCK(&g_decoderResource.resourceMutex);
    }

    *decoder = newDecoder;
    return 1;

fail:
    free_dv_decoder(&newDecoder);
    return 0;
}
Example #30
0
static void* worker_thread(void* arg)
{
    DVDecodeStreamConnect* connect = (DVDecodeStreamConnect*)arg;
    int status;
    int workerResult;
    int doneWaiting;

    while (!connect->stopped)
    {
        /* wait until a frame is ready */
        doneWaiting = 0;
        while (!doneWaiting && !connect->stopped)
        {
            /* wait for a frame */
            PTHREAD_MUTEX_LOCK(&connect->workerMutex);
            if (!connect->frameIsReady)
            {
                status = pthread_cond_wait(&connect->frameIsReadyCond, &connect->workerMutex);
                if (status != 0)
                {
                    ml_log_error("DV connect worker thread failed to wait for condition\n");
                    /* TODO: don't try again? */
                }
            }

            /* done waiting if there is a frame ready for processing */
            if (connect->frameIsReady)
            {
                /* worker will now be busy */
                connect->workerIsBusy = 1;
                connect->workerResult = 0;
                connect->frameIsReady = 0;
                doneWaiting = 1;
            }
            PTHREAD_MUTEX_UNLOCK(&connect->workerMutex);
        }

        /* no more work */
        if (connect->stopped)
        {
            break;
        }

        /* decode and send frame to sink */

        workerResult = decode_and_send(connect);


        /* signal that we are done with the frame */

        PTHREAD_MUTEX_LOCK(&connect->workerMutex);
        connect->workerResult = workerResult;
        connect->workerIsBusy = 0;
        status = pthread_cond_signal(&connect->workerIsBusyCond);
        if (status != 0)
        {
            ml_log_error("DV connect worker thread failed to send worker busy condition signal\n");
        }
        PTHREAD_MUTEX_UNLOCK(&connect->workerMutex);
    }

    pthread_exit((void*) 0);
}