Spaces:
Runtime error
Runtime error
/* | |
* Copyright (c) 2012 Georg Lippitsch <[email protected]> | |
* | |
* This file is part of FFmpeg. | |
* | |
* FFmpeg is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser General Public | |
* License as published by the Free Software Foundation; either | |
* version 2.1 of the License, or (at your option) any later version. | |
* | |
* FFmpeg is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
* Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public | |
* License along with FFmpeg; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
*/ | |
/** | |
* @file | |
* libiec61883 interface | |
*/ | |
/** | |
* For DV, one packet corresponds exactly to one frame. | |
* For HDV, these are MPEG2 transport stream packets. | |
* The queue is implemented as linked list. | |
*/ | |
typedef struct DVPacket { | |
uint8_t *buf; ///< actual buffer data | |
int len; ///< size of buffer allocated | |
struct DVPacket *next; ///< next DVPacket | |
} DVPacket; | |
struct iec61883_data { | |
AVClass *class; | |
raw1394handle_t raw1394; ///< handle for libraw1394 | |
iec61883_dv_fb_t iec61883_dv; ///< handle for libiec61883 when used with DV | |
iec61883_mpeg2_t iec61883_mpeg2; ///< handle for libiec61883 when used with HDV | |
DVDemuxContext *dv_demux; ///< generic DV muxing/demuxing context | |
MpegTSContext *mpeg_demux; ///< generic HDV muxing/demuxing context | |
DVPacket *queue_first; ///< first element of packet queue | |
DVPacket *queue_last; ///< last element of packet queue | |
char *device_guid; ///< to select one of multiple DV devices | |
int packets; ///< Number of packets queued | |
int max_packets; ///< Max. number of packets in queue | |
int bandwidth; ///< returned by libiec61883 | |
int channel; ///< returned by libiec61883 | |
int input_port; ///< returned by libiec61883 | |
int type; ///< Stream type, to distinguish DV/HDV | |
int node; ///< returned by libiec61883 | |
int output_port; ///< returned by libiec61883 | |
int thread_loop; ///< Condition for thread while-loop | |
int receiving; ///< True as soon data from device available | |
int receive_error; ///< Set in receive task in case of error | |
int eof; ///< True as soon as no more data available | |
struct pollfd raw1394_poll; ///< to poll for new data from libraw1394 | |
/** Parse function for DV/HDV differs, so this is set before packets arrive */ | |
int (*parse_queue)(struct iec61883_data *dv, AVPacket *pkt); | |
pthread_t receive_task_thread; | |
pthread_mutex_t mutex; | |
pthread_cond_t cond; | |
}; | |
static int iec61883_callback(unsigned char *data, int length, | |
int complete, void *callback_data) | |
{ | |
struct iec61883_data *dv = callback_data; | |
DVPacket *packet; | |
int ret; | |
pthread_mutex_lock(&dv->mutex); | |
if (dv->packets >= dv->max_packets) { | |
av_log(NULL, AV_LOG_ERROR, "DV packet queue overrun, dropping.\n"); | |
ret = 0; | |
goto exit; | |
} | |
packet = av_mallocz(sizeof(*packet)); | |
if (!packet) { | |
ret = -1; | |
goto exit; | |
} | |
packet->buf = av_malloc(length + AV_INPUT_BUFFER_PADDING_SIZE); | |
if (!packet->buf) { | |
av_free(packet); | |
ret = -1; | |
goto exit; | |
} | |
packet->len = length; | |
memcpy(packet->buf, data, length); | |
memset(packet->buf + length, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
if (dv->queue_first) { | |
dv->queue_last->next = packet; | |
dv->queue_last = packet; | |
} else { | |
dv->queue_first = packet; | |
dv->queue_last = packet; | |
} | |
dv->packets++; | |
ret = 0; | |
exit: | |
pthread_cond_broadcast(&dv->cond); | |
pthread_mutex_unlock(&dv->mutex); | |
return ret; | |
} | |
static void *iec61883_receive_task(void *opaque) | |
{ | |
struct iec61883_data *dv = (struct iec61883_data *)opaque; | |
int result; | |
while (dv->thread_loop) | |
{ | |
while ((result = poll(&dv->raw1394_poll, 1, 200)) < 0) { | |
if (!(errno == EAGAIN || errno == EINTR)) { | |
av_log(NULL, AV_LOG_ERROR, "Raw1394 poll error occurred.\n"); | |
dv->receive_error = AVERROR(EIO); | |
return NULL; | |
} | |
} | |
if (result > 0 && ((dv->raw1394_poll.revents & POLLIN) | |
|| (dv->raw1394_poll.revents & POLLPRI))) { | |
dv->receiving = 1; | |
raw1394_loop_iterate(dv->raw1394); | |
} else if (dv->receiving) { | |
av_log(NULL, AV_LOG_ERROR, "No more input data available\n"); | |
pthread_mutex_lock(&dv->mutex); | |
dv->eof = 1; | |
pthread_cond_broadcast(&dv->cond); | |
pthread_mutex_unlock(&dv->mutex); | |
dv->eof = 1; | |
return NULL; | |
} | |
} | |
return NULL; | |
} | |
static int iec61883_parse_queue_dv(struct iec61883_data *dv, AVPacket *pkt) | |
{ | |
DVPacket *packet; | |
int size; | |
size = avpriv_dv_get_packet(dv->dv_demux, pkt); | |
if (size > 0) | |
return size; | |
packet = dv->queue_first; | |
if (!packet) | |
return -1; | |
size = avpriv_dv_produce_packet(dv->dv_demux, pkt, | |
packet->buf, packet->len, -1); | |
dv->queue_first = packet->next; | |
if (size < 0) | |
av_free(packet->buf); | |
av_free(packet); | |
dv->packets--; | |
if (size < 0) | |
return -1; | |
if (av_packet_from_data(pkt, pkt->data, pkt->size) < 0) { | |
av_freep(&pkt->data); | |
av_packet_unref(pkt); | |
return -1; | |
} | |
return size; | |
} | |
static int iec61883_parse_queue_hdv(struct iec61883_data *dv, AVPacket *pkt) | |
{ | |
DVPacket *packet; | |
int size; | |
while (dv->queue_first) { | |
packet = dv->queue_first; | |
size = avpriv_mpegts_parse_packet(dv->mpeg_demux, pkt, packet->buf, | |
packet->len); | |
dv->queue_first = packet->next; | |
av_freep(&packet->buf); | |
av_freep(&packet); | |
dv->packets--; | |
if (size > 0) | |
return size; | |
} | |
return -1; | |
} | |
static int iec61883_read_header(AVFormatContext *context) | |
{ | |
struct iec61883_data *dv = context->priv_data; | |
struct raw1394_portinfo pinf[16]; | |
rom1394_directory rom_dir; | |
char *endptr; | |
int inport; | |
int nb_ports; | |
int port = -1; | |
int response; | |
int i, j = 0; | |
uint64_t guid = 0; | |
dv->input_port = -1; | |
dv->output_port = -1; | |
dv->channel = -1; | |
dv->raw1394 = raw1394_new_handle(); | |
if (!dv->raw1394) { | |
av_log(context, AV_LOG_ERROR, "Failed to open IEEE1394 interface.\n"); | |
return AVERROR(EIO); | |
} | |
if ((nb_ports = raw1394_get_port_info(dv->raw1394, pinf, 16)) < 0) { | |
av_log(context, AV_LOG_ERROR, "Failed to get number of IEEE1394 ports.\n"); | |
goto fail; | |
} | |
inport = strtol(context->url, &endptr, 10); | |
if (endptr != context->url && *endptr == '\0') { | |
av_log(context, AV_LOG_INFO, "Selecting IEEE1394 port: %d\n", inport); | |
j = inport; | |
nb_ports = inport + 1; | |
} else if (strcmp(context->url, "auto")) { | |
av_log(context, AV_LOG_ERROR, "Invalid input \"%s\", you should specify " | |
"\"auto\" for auto-detection, or the port number.\n", context->url); | |
goto fail; | |
} | |
if (dv->device_guid) { | |
if (sscanf(dv->device_guid, "%"SCNu64, &guid) != 1) { | |
av_log(context, AV_LOG_INFO, "Invalid dvguid parameter: %s\n", | |
dv->device_guid); | |
goto fail; | |
} | |
} | |
for (; j < nb_ports && port==-1; ++j) { | |
raw1394_destroy_handle(dv->raw1394); | |
if (!(dv->raw1394 = raw1394_new_handle_on_port(j))) { | |
av_log(context, AV_LOG_ERROR, "Failed setting IEEE1394 port.\n"); | |
goto fail; | |
} | |
for (i=0; i<raw1394_get_nodecount(dv->raw1394); ++i) { | |
/* Select device explicitly by GUID */ | |
if (guid > 1) { | |
if (guid == rom1394_get_guid(dv->raw1394, i)) { | |
dv->node = i; | |
port = j; | |
break; | |
} | |
} else { | |
/* Select first AV/C tape recorder player node */ | |
if (rom1394_get_directory(dv->raw1394, i, &rom_dir) < 0) | |
continue; | |
if (((rom1394_get_node_type(&rom_dir) == ROM1394_NODE_TYPE_AVC) && | |
avc1394_check_subunit_type(dv->raw1394, i, AVC1394_SUBUNIT_TYPE_VCR)) || | |
(rom_dir.unit_spec_id == MOTDCT_SPEC_ID)) { | |
rom1394_free_directory(&rom_dir); | |
dv->node = i; | |
port = j; | |
break; | |
} | |
rom1394_free_directory(&rom_dir); | |
} | |
} | |
} | |
if (port == -1) { | |
av_log(context, AV_LOG_ERROR, "No AV/C devices found.\n"); | |
goto fail; | |
} | |
/* Provide bus sanity for multiple connections */ | |
iec61883_cmp_normalize_output(dv->raw1394, 0xffc0 | dv->node); | |
/* Find out if device is DV or HDV */ | |
if (dv->type == IEC61883_AUTO) { | |
response = avc1394_transaction(dv->raw1394, dv->node, | |
AVC1394_CTYPE_STATUS | | |
AVC1394_SUBUNIT_TYPE_TAPE_RECORDER | | |
AVC1394_SUBUNIT_ID_0 | | |
AVC1394_VCR_COMMAND_OUTPUT_SIGNAL_MODE | | |
0xFF, 2); | |
response = AVC1394_GET_OPERAND0(response); | |
dv->type = (response == 0x10 || response == 0x90 || response == 0x1A || response == 0x9A) ? | |
IEC61883_HDV : IEC61883_DV; | |
} | |
/* Connect to device, and do initialization */ | |
dv->channel = iec61883_cmp_connect(dv->raw1394, dv->node, &dv->output_port, | |
raw1394_get_local_id(dv->raw1394), | |
&dv->input_port, &dv->bandwidth); | |
if (dv->channel < 0) | |
dv->channel = 63; | |
if (!dv->max_packets) | |
dv->max_packets = 100; | |
if (CONFIG_MPEGTS_DEMUXER && dv->type == IEC61883_HDV) { | |
/* Init HDV receive */ | |
avformat_new_stream(context, NULL); | |
dv->mpeg_demux = avpriv_mpegts_parse_open(context); | |
if (!dv->mpeg_demux) | |
goto fail; | |
dv->parse_queue = iec61883_parse_queue_hdv; | |
dv->iec61883_mpeg2 = iec61883_mpeg2_recv_init(dv->raw1394, | |
(iec61883_mpeg2_recv_t)iec61883_callback, | |
dv); | |
dv->max_packets *= 766; | |
} else { | |
/* Init DV receive */ | |
dv->dv_demux = avpriv_dv_init_demux(context); | |
if (!dv->dv_demux) | |
goto fail; | |
dv->parse_queue = iec61883_parse_queue_dv; | |
dv->iec61883_dv = iec61883_dv_fb_init(dv->raw1394, iec61883_callback, dv); | |
} | |
dv->raw1394_poll.fd = raw1394_get_fd(dv->raw1394); | |
dv->raw1394_poll.events = POLLIN | POLLERR | POLLHUP | POLLPRI; | |
/* Actually start receiving */ | |
if (dv->type == IEC61883_HDV) | |
iec61883_mpeg2_recv_start(dv->iec61883_mpeg2, dv->channel); | |
else | |
iec61883_dv_fb_start(dv->iec61883_dv, dv->channel); | |
dv->thread_loop = 1; | |
if (pthread_mutex_init(&dv->mutex, NULL)) | |
goto fail; | |
if (pthread_cond_init(&dv->cond, NULL)) | |
goto fail; | |
if (pthread_create(&dv->receive_task_thread, NULL, iec61883_receive_task, dv)) | |
goto fail; | |
return 0; | |
fail: | |
raw1394_destroy_handle(dv->raw1394); | |
return AVERROR(EIO); | |
} | |
static int iec61883_read_packet(AVFormatContext *context, AVPacket *pkt) | |
{ | |
struct iec61883_data *dv = context->priv_data; | |
int size; | |
/** | |
* Try to parse frames from queue | |
*/ | |
pthread_mutex_lock(&dv->mutex); | |
while ((size = dv->parse_queue(dv, pkt)) == -1) | |
if (!dv->eof) | |
pthread_cond_wait(&dv->cond, &dv->mutex); | |
else | |
break; | |
pthread_mutex_unlock(&dv->mutex); | |
int result; | |
while ((size = dv->parse_queue(dv, pkt)) == -1) { | |
iec61883_receive_task((void *)dv); | |
if (dv->receive_error) | |
return dv->receive_error; | |
} | |
return size; | |
} | |
static int iec61883_close(AVFormatContext *context) | |
{ | |
struct iec61883_data *dv = context->priv_data; | |
dv->thread_loop = 0; | |
pthread_join(dv->receive_task_thread, NULL); | |
pthread_cond_destroy(&dv->cond); | |
pthread_mutex_destroy(&dv->mutex); | |
if (CONFIG_MPEGTS_DEMUXER && dv->type == IEC61883_HDV) { | |
iec61883_mpeg2_recv_stop(dv->iec61883_mpeg2); | |
iec61883_mpeg2_close(dv->iec61883_mpeg2); | |
avpriv_mpegts_parse_close(dv->mpeg_demux); | |
} else { | |
iec61883_dv_fb_stop(dv->iec61883_dv); | |
iec61883_dv_fb_close(dv->iec61883_dv); | |
av_freep(&dv->dv_demux); | |
} | |
while (dv->queue_first) { | |
DVPacket *packet = dv->queue_first; | |
dv->queue_first = packet->next; | |
av_freep(&packet->buf); | |
av_freep(&packet); | |
} | |
iec61883_cmp_disconnect(dv->raw1394, dv->node, dv->output_port, | |
raw1394_get_local_id(dv->raw1394), | |
dv->input_port, dv->channel, dv->bandwidth); | |
raw1394_destroy_handle(dv->raw1394); | |
return 0; | |
} | |
static const AVOption options[] = { | |
{ "dvtype", "override autodetection of DV/HDV", offsetof(struct iec61883_data, type), AV_OPT_TYPE_INT, {.i64 = IEC61883_AUTO}, IEC61883_AUTO, IEC61883_HDV, AV_OPT_FLAG_DECODING_PARAM, "dvtype" }, | |
{ "auto", "auto detect DV/HDV", 0, AV_OPT_TYPE_CONST, {.i64 = IEC61883_AUTO}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" }, | |
{ "dv", "force device being treated as DV device", 0, AV_OPT_TYPE_CONST, {.i64 = IEC61883_DV}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" }, | |
{ "hdv" , "force device being treated as HDV device", 0, AV_OPT_TYPE_CONST, {.i64 = IEC61883_HDV}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "dvtype" }, | |
{ "dvbuffer", "set queue buffer size (in packets)", offsetof(struct iec61883_data, max_packets), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, | |
{ "dvguid", "select one of multiple DV devices by its GUID", offsetof(struct iec61883_data, device_guid), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, | |
{ NULL }, | |
}; | |
static const AVClass iec61883_class = { | |
.class_name = "iec61883 indev", | |
.item_name = av_default_item_name, | |
.option = options, | |
.version = LIBAVUTIL_VERSION_INT, | |
.category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, | |
}; | |
const AVInputFormat ff_iec61883_demuxer = { | |
.name = "iec61883", | |
.long_name = NULL_IF_CONFIG_SMALL("libiec61883 (new DV1394) A/V input device"), | |
.priv_data_size = sizeof(struct iec61883_data), | |
.read_header = iec61883_read_header, | |
.read_packet = iec61883_read_packet, | |
.read_close = iec61883_close, | |
.flags = AVFMT_NOFILE, | |
.priv_class = &iec61883_class, | |
}; | |