Пример #1
0
struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target,
				unsigned int target_size,
				const char *mimetype, const uint8_t *who,
				unsigned int who_size)
{
	struct obex_mime_type_driver *driver;

	driver = find_driver(target, target_size, mimetype, who, who_size);
	if (driver == NULL) {
		if (who != NULL) {
			/* Fallback to non-who specific */
			driver = find_driver(target, target_size, mimetype, NULL, 0);
			if (driver != NULL)
				return driver;
		}

		if (mimetype != NULL)
			/* Fallback to target default */
			driver = find_driver(target, target_size, NULL, NULL, 0);

		if (driver == NULL)
			/* Fallback to general default */
			driver = find_driver(NULL, 0, NULL, NULL, 0);
	}

	return driver;
}
Пример #2
0
CRYSTAX_LOCAL
int open(const char *path, int oflag, va_list &vl)
{
    DBG("path=%s, oflag=%d (%s)", path, oflag, mode_s(oflag));

    driver_t *driver = find_driver(path);
    if (!driver)
        return -1;

    DBG("use driver %s (%s)", driver->name(), driver->info());
    int extfd = driver->open(path, oflag, vl);
    DBG("extfd=%d", extfd);

    if (extfd == -1)
        return -1;

    int fd = alloc_fd(path, extfd, driver);
    if (fd < 0)
    {
        ERR("can't alloc fd, return -1");
        driver->close(extfd);
        errno = EMFILE;
        return -1;
    }

    DBG("return fd=%d", fd);
    return fd;
}
Пример #3
0
CRYSTAX_LOCAL
int symlink(const char *src, const char *dst)
{
    DBG("src=%s, dst=%s", src, dst);

    driver_t *driver = find_driver(src);
    driver_t *driver2 = find_driver(dst);
    if (driver != driver2)
    {
        ERR("symlink across sources not supported yet");
        errno = EXDEV;
        return -1;
    }

    return driver->symlink(src, dst);
}
Пример #4
0
static struct snobj *handle_create_port(struct snobj *arg)
{
	const char *driver_name;
	const struct driver *driver;
	struct port *port;

	struct snobj *r;
	struct snobj *err;

	driver_name = snobj_eval_str(arg, "driver");
	if (!driver_name)
		return snobj_err(EINVAL, "Missing 'driver' field in arg");

	driver = find_driver(driver_name);
	if (!driver)
		return snobj_err(ENOENT, "No port driver '%s' found",
				driver_name);

	port = create_port(snobj_eval_str(arg, "name"), driver, 
			snobj_eval(arg, "arg"), &err);
	if (!port)
		return err;

	printf("Port %s created at %p\n", port->name, port);

	r = snobj_map();
	snobj_map_set(r, "name", snobj_str(port->name));

	return r;
}
Пример #5
0
CRYSTAX_LOCAL
int lstat(const char *path, struct stat *st)
{
    DBG("path=%s, st=%p", path, st);

    driver_t *driver = find_driver(path);
    if (!driver)
        return -1;

    return driver->lstat(path, st);
}
Пример #6
0
CRYSTAX_LOCAL
int rmdir(const char *path)
{
    DBG("path=%s", path);

    driver_t *driver = find_driver(path);
    if (!driver)
        return -1;

    return driver->rmdir(path);
}
Пример #7
0
CRYSTAX_LOCAL
int readlink(const char *path, char *buf, size_t bufsize)
{
    DBG("path=%s, buf=%p, bufsize=%lu", path, buf, (unsigned long)bufsize);

    driver_t *driver = find_driver(path);
    if (!driver)
        return -1;

    return driver->readlink(path, buf, bufsize);
}
Пример #8
0
CRYSTAX_LOCAL
int chown(const char *path, uid_t uid, gid_t gid)
{
    DBG("path=%s, uid=%u, gid=%u", path, (unsigned)uid, (unsigned)gid);

    driver_t *driver = find_driver(path);
    if (!driver)
        return -1;

    return driver->chown(path, uid, gid);
}
Пример #9
0
/*
 *	pccard_add_driver - Add a new driver to the list of
 *	drivers available for allocation.
 */
void
pccard_add_driver(struct pccard_drv *dp)
{
	/*
	 *	If already loaded, then reject the driver.
	 */
	if (find_driver(dp->name)) {
		printf("Driver %s already loaded\n", dp->name);
		return;
	}
	printf("pccard driver %s added\n", dp->name);
	dp->next = drivers;
	drivers = dp;
}
Пример #10
0
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders)
{
    assert(!d_audio->ad_driver);
    audio_reset_decoding(d_audio);

    struct mp_decoder_entry *decoder = NULL;
    struct mp_decoder_list *list =
        audio_select_decoders(d_audio->header->codec, audio_decoders);

    mp_print_decoders(MSGT_DECAUDIO, MSGL_V, "Codec list:", list);

    for (int n = 0; n < list->num_entries; n++) {
        struct mp_decoder_entry *sel = &list->entries[n];
        const struct ad_functions *driver = find_driver(sel->family);
        if (!driver)
            continue;
        mp_msg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder %s:%s\n",
                sel->family, sel->decoder);
        d_audio->ad_driver = driver;
        if (init_audio_codec(d_audio, sel->decoder)) {
            decoder = sel;
            break;
        }
        mp_msg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for "
                "%s:%s\n", sel->family, sel->decoder);
    }

    if (d_audio->ad_driver) {
        d_audio->decoder_desc =
            talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family,
                            decoder->decoder);
        mp_msg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s\n",
               d_audio->decoder_desc);
        mp_msg(MSGT_DECAUDIO, MSGL_V,
               "AUDIO: %d Hz, %d ch, %s\n",
               d_audio->decoded.rate, d_audio->decoded.channels.num,
               af_fmt_to_str(d_audio->decoded.format));
        mp_msg(MSGT_IDENTIFY, MSGL_INFO,
               "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n",
               d_audio->i_bps * 8, d_audio->decoded.rate,
               d_audio->decoded.channels.num);
    } else {
        mp_msg(MSGT_DECAUDIO, MSGL_ERR,
               "Failed to initialize an audio decoder for codec '%s'.\n",
               d_audio->header->codec ? d_audio->header->codec : "<unknown>");
    }

    talloc_free(list);
    return !!d_audio->ad_driver;
}
Пример #11
0
static dentry_t* devfs_lookup(struct _fs_instance_t *instance, struct _dentry_t* dentry, const char * name) {
    //TODO: gérer dentry pour avoir des sous-dossiers.

    driver_entry *drentry = find_driver(name);
    if (drentry != NULL) {
        inode_t *inode = kmalloc(sizeof(inode_t));
        inode->i_ino = 42; //XXX
        inode->i_mode = 0755;
        inode->i_uid = 0;
        inode->i_gid = 0;
        inode->i_size = 0;
        inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_dtime = 0; // XXX
        inode->i_nlink = 1;
        inode->i_blocks = 1;
        inode->i_count = 0;
        inode->i_instance = instance;
        inode->i_fops = kmalloc(sizeof(open_file_operations_t));
        inode->i_fs_specific = (chardev_interfaces*)(drentry->di);

        switch(drentry->type) {
        case CHARDEV:
            inode->i_fops->readdir = NULL;
            inode->i_fops->open = ((chardev_interfaces*)(drentry->di))->open;
            inode->i_fops->write = ((chardev_interfaces*)(drentry->di))->write;
            inode->i_fops->read = ((chardev_interfaces*)(drentry->di))->read;
            inode->i_fops->seek = NULL; /* à implémenter */
            inode->i_fops->close = ((chardev_interfaces*)(drentry->di))->close;
            inode->i_fops->ioctl = ((chardev_interfaces*)(drentry->di))->ioctl;

            break;
        case BLKDEV:
            inode->i_fops->readdir = NULL;
            inode->i_fops->open = ((blkdev_interfaces*)(drentry->di))->open;
            inode->i_fops->write = NULL; /* à implémenter */
            inode->i_fops->read = NULL; /* à implémenter */
            inode->i_fops->seek = NULL; /* à implémenter */
            inode->i_fops->close = ((blkdev_interfaces*)(drentry->di))->close;
            inode->i_fops->ioctl = ((blkdev_interfaces*)(drentry->di))->ioctl;

            break;
        }
        dentry_t *d = kmalloc(sizeof(dentry_t));
        char *n = strdup(name);
        d->d_name = (const char*)n;
        d->d_inode = inode;
        d->d_pdentry = dentry;
        return d;
    }
    return NULL;
}
Пример #12
0
static const struct timer *
timer_open(const char *dname)
{
    const struct timer *tmr = NULL;
    const char *param = NULL;

    tmr = find_driver(dname, &param, ofbp_timer_start);
    if (tmr && !tmr->open(param))
        return tmr;

    fprintf(stderr, "Timer driver failed or missing\n");

    return NULL;
}
Пример #13
0
int init_best_audio_codec(sh_audio_t *sh_audio, char *audio_decoders)
{
    assert(!sh_audio->initialized);

    struct mp_decoder_entry *decoder = NULL;
    struct mp_decoder_list *list =
        mp_select_audio_decoders(sh_audio->gsh->codec, audio_decoders);

    mp_print_decoders(MSGT_DECAUDIO, MSGL_V, "Codec list:", list);

    for (int n = 0; n < list->num_entries; n++) {
        struct mp_decoder_entry *sel = &list->entries[n];
        const struct ad_functions *driver = find_driver(sel->family);
        if (!driver)
            continue;
        mp_tmsg(MSGT_DECAUDIO, MSGL_V, "Opening audio decoder %s:%s\n",
                sel->family, sel->decoder);
        sh_audio->ad_driver = driver;
        if (init_audio_codec(sh_audio, sel->decoder)) {
            decoder = sel;
            break;
        }
        sh_audio->ad_driver = NULL;
        mp_tmsg(MSGT_DECAUDIO, MSGL_WARN, "Audio decoder init failed for "
                "%s:%s\n", sel->family, sel->decoder);
    }

    if (sh_audio->initialized) {
        sh_audio->gsh->decoder_desc =
            talloc_asprintf(NULL, "%s [%s:%s]", decoder->desc, decoder->family,
                            decoder->decoder);
        mp_msg(MSGT_DECAUDIO, MSGL_INFO, "Selected audio codec: %s\n",
               sh_audio->gsh->decoder_desc);
        mp_msg(MSGT_DECAUDIO, MSGL_V,
               "AUDIO: %d Hz, %d ch, %s\n",
               sh_audio->samplerate, sh_audio->channels.num,
               af_fmt2str_short(sh_audio->sample_format));
        mp_msg(MSGT_IDENTIFY, MSGL_INFO,
               "ID_AUDIO_BITRATE=%d\nID_AUDIO_RATE=%d\n" "ID_AUDIO_NCH=%d\n",
               sh_audio->i_bps * 8, sh_audio->samplerate, sh_audio->channels.num);
    } else {
        mp_msg(MSGT_DECAUDIO, MSGL_ERR,
               "Failed to initialize an audio decoder for codec '%s'.\n",
               sh_audio->gsh->codec ? sh_audio->gsh->codec : "<unknown>");
    }

    talloc_free(list);
    return sh_audio->initialized;
}
Пример #14
0
static const struct display *
display_open(const char *dname, struct frame_format *dp,
             struct frame_format *ff)
{
    const struct display *disp = NULL;
    const char *param = NULL;

    disp = find_driver(dname, &param, ofbp_display_start);
    if (disp && !disp->open(param, dp, ff))
        return disp;

    fprintf(stderr, "Display driver failed or missing\n");

    return NULL;
}
Пример #15
0
bool video_init_best_codec(struct dec_video *d_video, char* video_decoders)
{
    assert(!d_video->vd_driver);
    video_reset(d_video);
    d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision

    struct mp_decoder_entry *decoder = NULL;
    struct mp_decoder_list *list =
        mp_select_video_decoders(d_video->header->codec->codec, video_decoders);

    mp_print_decoders(d_video->log, MSGL_V, "Codec list:", list);

    for (int n = 0; n < list->num_entries; n++) {
        struct mp_decoder_entry *sel = &list->entries[n];
        const struct vd_functions *driver = find_driver(sel->family);
        if (!driver)
            continue;
        MP_VERBOSE(d_video, "Opening video decoder %s:%s\n",
                   sel->family, sel->decoder);
        d_video->vd_driver = driver;
        if (init_video_codec(d_video, sel->decoder)) {
            decoder = sel;
            break;
        }
        d_video->vd_driver = NULL;
        MP_WARN(d_video, "Video decoder init failed for "
                "%s:%s\n", sel->family, sel->decoder);
    }

    if (d_video->vd_driver) {
        d_video->decoder_desc =
            talloc_asprintf(d_video, "%s [%s:%s]", decoder->desc, decoder->family,
                            decoder->decoder);
        MP_VERBOSE(d_video, "Selected video codec: %s\n", d_video->decoder_desc);
    } else {
        MP_ERR(d_video, "Failed to initialize a video decoder for codec '%s'.\n",
               d_video->header->codec->codec);
    }

    if (d_video->header->missing_timestamps) {
        MP_WARN(d_video, "This stream has no timestamps!\n");
        MP_WARN(d_video, "Making up playback time using %f FPS.\n", d_video->fps);
        MP_WARN(d_video, "Seeking will probably fail badly.\n");
    }

    talloc_free(list);
    return !!d_video->vd_driver;
}
Пример #16
0
static const struct pixconv *
pixconv_open(const char *name, const struct frame_format *ffmt,
             const struct frame_format *dfmt)
{
    const struct pixconv **start = ofbp_pixconv_start;
    const struct pixconv *conv;

    do {
        conv = find_driver(name, NULL, start);
        if (conv && !conv->open(ffmt, dfmt))
            return conv;
    } while (*start++);

    fprintf(stderr, "No pixel converter found\n");

    return NULL;
}
Пример #17
0
bool video_init_best_codec(struct dec_video *d_video, char* video_decoders)
{
    assert(!d_video->vd_driver);
    video_reset_decoding(d_video);
    d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision

    struct mp_decoder_entry *decoder = NULL;
    struct mp_decoder_list *list =
        mp_select_video_decoders(d_video->header->codec, video_decoders);

    mp_print_decoders(MSGT_DECVIDEO, MSGL_V, "Codec list:", list);

    for (int n = 0; n < list->num_entries; n++) {
        struct mp_decoder_entry *sel = &list->entries[n];
        const struct vd_functions *driver = find_driver(sel->family);
        if (!driver)
            continue;
        mp_msg(MSGT_DECVIDEO, MSGL_V, "Opening video decoder %s:%s\n",
                sel->family, sel->decoder);
        d_video->vd_driver = driver;
        if (init_video_codec(d_video, sel->decoder)) {
            decoder = sel;
            break;
        }
        d_video->vd_driver = NULL;
        mp_msg(MSGT_DECVIDEO, MSGL_WARN, "Video decoder init failed for "
                "%s:%s\n", sel->family, sel->decoder);
    }

    if (d_video->vd_driver) {
        d_video->decoder_desc =
            talloc_asprintf(d_video, "%s [%s:%s]", decoder->desc, decoder->family,
                            decoder->decoder);
        mp_msg(MSGT_DECVIDEO, MSGL_INFO, "Selected video codec: %s\n",
               d_video->decoder_desc);
    } else {
        mp_msg(MSGT_DECVIDEO, MSGL_ERR,
               "Failed to initialize a video decoder for codec '%s'.\n",
               d_video->header->codec ? d_video->header->codec : "<unknown>");
    }

    talloc_free(list);
    return !!d_video->vd_driver;
}
Пример #18
0
void device_init(void)
{
  int i;
  io_descriptor_t *descriptor;
  drivers_available_t *driver;

  descriptor = (io_descriptor_t*)IO_DESCRIPTOR_AREA;

  /* search _all_ descriptors (see YAMS documentation) */
  for (i=0; i<YAMS_MAX_DEVICES; i++) {
    if (descriptor->type != 0) {
      driver = find_driver(descriptor->type);
      if (driver == NULL) {
        kprintf("Warning: Unknown hardware device type "
                "0x%3.3x at 0x%8.8x\n",
                descriptor->type, descriptor->io_area_base);
      } else {
        if (descriptor->irq != 0xffffffff)
          kprintf("Device: Type 0x%3.3x at 0x%8.8x irq 0x%x "
                  "driver '%s'\n",
                  descriptor->type, descriptor->io_area_base,
                  descriptor->irq, driver->name);
        else
          kprintf("Device: Type 0x%3.3x at 0x%8.8x no irq  "
                  "driver '%s'\n",
                  descriptor->type, descriptor->io_area_base,
                  driver->name);

        device_table[number_of_devices]=driver->initfunc(descriptor);
        if (device_table[number_of_devices] != NULL) {
          number_of_devices++;
          if (number_of_devices >= CONFIG_MAX_DEVICES)
            break;
        }
      }
    }
    descriptor++;
  }

}
Пример #19
0
int audio_init_best_codec(struct dec_audio *d_audio, char *audio_decoders)
{
    assert(!d_audio->ad_driver);
    audio_reset_decoding(d_audio);

    struct mp_decoder_entry *decoder = NULL;
    struct mp_decoder_list *list =
        audio_select_decoders(d_audio->header->codec, audio_decoders);

    mp_print_decoders(d_audio->log, MSGL_V, "Codec list:", list);

    for (int n = 0; n < list->num_entries; n++) {
        struct mp_decoder_entry *sel = &list->entries[n];
        const struct ad_functions *driver = find_driver(sel->family);
        if (!driver)
            continue;
        MP_VERBOSE(d_audio, "Opening audio decoder %s:%s\n",
                   sel->family, sel->decoder);
        d_audio->ad_driver = driver;
        if (init_audio_codec(d_audio, sel->decoder)) {
            decoder = sel;
            break;
        }
        MP_WARN(d_audio, "Audio decoder init failed for "
                "%s:%s\n", sel->family, sel->decoder);
    }

    if (d_audio->ad_driver) {
        d_audio->decoder_desc =
            talloc_asprintf(d_audio, "%s [%s:%s]", decoder->desc, decoder->family,
                            decoder->decoder);
        MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
    } else {
        MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
               d_audio->header->codec ? d_audio->header->codec : "<unknown>");
    }

    talloc_free(list);
    return !!d_audio->ad_driver;
}
Пример #20
0
static void write_nets(struct netlist_manager *m, FILE *fd)
{
	struct netlist_net *net;
	struct netlist_branch *driver;
	struct netlist_branch *target;
	
	net = m->nhead;
	while(net != NULL) {
		driver = find_driver(net);
		if(driver != NULL) {
			target = net->head;
			while(target != NULL) {
				if(!target->output)
					fprintf(fd, "I%08x:%s -> I%08x:%s;\n",
						driver->inst->uid, driver->inst->p->output_names[driver->pin_index],
						target->inst->uid, target->inst->p->input_names[target->pin_index]);
				target = target->next;
			}
		}
		net = net->next;
	}
}
Пример #21
0
int obex_mime_type_driver_register(struct obex_mime_type_driver *driver)
{
	if (!driver) {
		error("Invalid driver");
		return -EINVAL;
	}

	if (find_driver(driver->target, driver->target_size, driver->mimetype,
					driver->who, driver->who_size)) {
		error("Permission denied: %s could not be registered",
				driver->mimetype);
		return -EPERM;
	}

	if (driver->set_io_watch == NULL)
		driver->set_io_watch = set_io_watch;

	DBG("driver %p mimetype %s registered", driver, driver->mimetype);

	drivers = g_slist_append(drivers, driver);

	return 0;
}
Пример #22
0
int obex_service_driver_register(struct obex_service_driver *driver)
{
	if (!driver) {
		error("Invalid driver");
		return -EINVAL;
	}

	if (find_driver(driver->service)) {
		error("Permission denied: service %s already registered",
			driver->name);
		return -EPERM;
	}

	DBG("driver %p service %s registered", driver, driver->name);

	/* Drivers that support who has priority */
	if (driver->who)
		drivers = g_slist_prepend(drivers, driver);
	else
		drivers = g_slist_append(drivers, driver);

	return 0;
}
Пример #23
0
static int old_capi_manufacturer(unsigned int cmd, void *data)
{
	avmb1_loadandconfigdef ldef;
	avmb1_extcarddef cdef;
	avmb1_resetdef rdef;
	avmb1_getdef gdef;
	struct capi_driver *driver;
	struct capi_ctr *card;
	capicardparams cparams;
	capiloaddata ldata;
	int retval;

	switch (cmd) {
	case AVMB1_ADDCARD:
	case AVMB1_ADDCARD_WITH_TYPE:
		if (cmd == AVMB1_ADDCARD) {
		   if ((retval = copy_from_user((void *) &cdef, data,
					    sizeof(avmb1_carddef))))
			   return retval;
		   cdef.cardtype = AVM_CARDTYPE_B1;
		} else {
		   if ((retval = copy_from_user((void *) &cdef, data,
					    sizeof(avmb1_extcarddef))))
			   return retval;
		}
		cparams.port = cdef.port;
		cparams.irq = cdef.irq;
		cparams.cardnr = cdef.cardnr;

                switch (cdef.cardtype) {
			case AVM_CARDTYPE_B1:
				driver = find_driver("b1isa");
				break;
			case AVM_CARDTYPE_T1:
				driver = find_driver("t1isa");
				break;
			default:
				driver = 0;
				break;
		}
		if (!driver) {
			printk(KERN_ERR "kcapi: driver not loaded.\n");
			return -EIO;
		}
		if (!driver->add_card) {
			printk(KERN_ERR "kcapi: driver has no add card function.\n");
			return -EIO;
		}

		return driver->add_card(driver, &cparams);

	case AVMB1_LOAD:
	case AVMB1_LOAD_AND_CONFIG:

		if (cmd == AVMB1_LOAD) {
			if ((retval = copy_from_user((void *) &ldef, data,
						sizeof(avmb1_loaddef))))
				return retval;
			ldef.t4config.len = 0;
			ldef.t4config.data = 0;
		} else {
			if ((retval = copy_from_user((void *) &ldef, data,
					    	sizeof(avmb1_loadandconfigdef))))
				return retval;
		}
		if (!VALID_CARD(ldef.contr))
			return -ESRCH;

		card = CARD(ldef.contr);
		if (card->cardstate == CARD_FREE)
			return -ESRCH;
		if (card->driver->load_firmware == 0) {
			printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
			return -ESRCH;
		}

		if (ldef.t4file.len <= 0) {
			printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
			return -EINVAL;
		}
		if (ldef.t4file.data == 0) {
			printk(KERN_DEBUG "kcapi: load: invalid parameter: dataptr is 0\n");
			return -EINVAL;
		}

		ldata.firmware.user = 1;
		ldata.firmware.data = ldef.t4file.data;
		ldata.firmware.len = ldef.t4file.len;
		ldata.configuration.user = 1;
		ldata.configuration.data = ldef.t4config.data;
		ldata.configuration.len = ldef.t4config.len;

		if (card->cardstate != CARD_DETECTED) {
			printk(KERN_INFO "kcapi: load: contr=%d not in detect state\n", ldef.contr);
			return -EBUSY;
		}
		card->cardstate = CARD_LOADING;

		retval = card->driver->load_firmware(card, &ldata);

		if (retval) {
			card->cardstate = CARD_DETECTED;
			return retval;
		}

		while (card->cardstate != CARD_RUNNING) {

			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(HZ/10);	/* 0.1 sec */

			if (signal_pending(current))
				return -EINTR;
		}
		return 0;

	case AVMB1_RESETCARD:
		if ((retval = copy_from_user((void *) &rdef, data,
					 sizeof(avmb1_resetdef))))
			return retval;
		if (!VALID_CARD(rdef.contr))
			return -ESRCH;
		card = CARD(rdef.contr);

		if (card->cardstate == CARD_FREE)
			return -ESRCH;
		if (card->cardstate == CARD_DETECTED)
			return 0;

		card->driver->reset_ctr(card);

		while (card->cardstate > CARD_DETECTED) {

			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(HZ/10);	/* 0.1 sec */

			if (signal_pending(current))
				return -EINTR;
		}
		return 0;

	case AVMB1_GET_CARDINFO:
		if ((retval = copy_from_user((void *) &gdef, data,
					 sizeof(avmb1_getdef))))
			return retval;

		if (!VALID_CARD(gdef.contr))
			return -ESRCH;

		card = CARD(gdef.contr);

		if (card->cardstate == CARD_FREE)
			return -ESRCH;

		gdef.cardstate = card->cardstate;
		if (card->driver == find_driver("t1isa"))
			gdef.cardtype = AVM_CARDTYPE_T1;
		else gdef.cardtype = AVM_CARDTYPE_B1;

		if ((retval = copy_to_user(data, (void *) &gdef,
					 sizeof(avmb1_getdef))))
			return retval;

		return 0;

	case AVMB1_REMOVECARD:
		if ((retval = copy_from_user((void *) &rdef, data,
					 sizeof(avmb1_resetdef))))
			return retval;

		if (!VALID_CARD(rdef.contr))
			return -ESRCH;
		card = CARD(rdef.contr);

		if (card->cardstate == CARD_FREE)
			return -ESRCH;

		if (card->cardstate != CARD_DETECTED)
			return -EBUSY;

		card->driver->remove_ctr(card);

		while (card->cardstate != CARD_FREE) {

			set_current_state(TASK_INTERRUPTIBLE);
			schedule_timeout(HZ/10);	/* 0.1 sec */

			if (signal_pending(current))
				return -EINTR;
		}
		return 0;
	}
Пример #24
0
/*
 * main:
 *	Main program for local process
 */
int
main(int ac, char **av)
{
	char *term;
	int c;
	int enter_status;
	bool Query_driver = false;
	bool Show_scores = false;

	enter_status = env_init(Q_CLOAK);
	while ((c = getopt(ac, av, "Sbcfh:l:mn:op:qst:w:")) != -1) {
		switch (c) {
		case 'l':	/* rsh compatibility */
		case 'n':
			(void) strncpy(name, optarg, sizeof(name));
			break;
		case 't':
			team = *optarg;
			if (!isdigit((unsigned char)team)) {
				warnx("Team names must be numeric");
				team = ' ';
			}
			break;
		case 'o':
#ifndef OTTO
			warnx("The -o flag is reserved for future use.");
			goto usage;
#else
			Otto_mode = true;
			break;
#endif
		case 'm':
#ifdef MONITOR
			Am_monitor = true;
#else
			warnx("The monitor was not compiled in.");
#endif
			break;
#ifdef INTERNET
		case 'S':
			Show_scores = true;
			break;
		case 'q':	/* query whether hunt is running */
			Query_driver = true;
			break;
		case 'w':
			Send_message = optarg;
			break;
		case 'h':
			contacthost = optarg;
			break;
		case 'p':
			contactportstr = optarg;
			contactport = atoi(contactportstr);
			break;
#else
		case 'S':
		case 'q':
		case 'w':
		case 'h':
		case 'p':
			wanrx("Need TCP/IP for S, q, w, h, and p options.");
			break;
#endif
		case 'c':
			enter_status = Q_CLOAK;
			break;
		case 'f':
#ifdef FLY
			enter_status = Q_FLY;
#else
			warnx("The flying code was not compiled in.");
#endif
			break;
		case 's':
			enter_status = Q_SCAN;
			break;
		case 'b':
			no_beep = !no_beep;
			break;
		default:
		usage:
			fputs(
"usage:\thunt [-qmcsfS] [-n name] [-t team] [-p port] [-w message] [host]\n",
			stderr);
			exit(1);
		}
	}
#ifdef INTERNET
	if (optind + 1 < ac)
		goto usage;
	else if (optind + 1 == ac)
		contacthost = av[ac - 1];
#else
	if (optind < ac)
		goto usage;
#endif

#ifdef INTERNET
	serverlist_setup(contacthost, contactport);

	if (Show_scores) {
		const struct sockaddr_storage *host;
		socklen_t hostlen;
		u_short msg = C_SCORES;
		unsigned i;

		serverlist_query(msg);
		for (i = 0; i < serverlist_num(); i++) {
			host = serverlist_gethost(i, &hostlen);
			dump_scores(host, hostlen);
		}
		exit(0);
	}
	if (Query_driver) {
		const struct sockaddr_storage *host;
		socklen_t hostlen;
		u_short msg = C_MESSAGE;
		u_short num_players;
		unsigned i;

		serverlist_query(msg);
		for (i = 0; i < serverlist_num(); i++) {
			host = serverlist_gethost(i, &hostlen);
			num_players = ntohs(serverlist_getresponse(i));

			printf("%d player%s hunting on %s!\n",
				num_players, (num_players == 1) ? "" : "s",
				lookuphost(host, hostlen));
		}
		exit(0);
	}
#endif
#ifdef OTTO
	if (Otto_mode)
		(void) strncpy(name, "otto", sizeof(name));
	else
#endif
	fill_in_blanks();

	(void) fflush(stdout);
	if (!isatty(0) || (term = getenv("TERM")) == NULL)
		errx(1, "no terminal type");
	if (!initscr())
		errx(0, "couldn't initialize screen");
	(void) noecho();
	(void) cbreak();
	in_visual = true;
	if (LINES < SCREEN_HEIGHT || COLS < SCREEN_WIDTH)
		leavex(1, "Need a larger window");
	clear_the_screen();
	(void) signal(SIGINT, intr);
	(void) signal(SIGTERM, sigterm);
	(void) signal(SIGUSR1, sigusr1);
	(void) signal(SIGPIPE, SIG_IGN);

	for (;;) {
#ifdef INTERNET
		find_driver();

		if (Daemon.sin_port == 0)
			leavex(1, "Game not found, try again");

	jump_in:
		do {
			int option;

			huntsocket = socket(SOCK_FAMILY, SOCK_STREAM, 0);
			if (huntsocket < 0)
				err(1, "socket");
			option = 1;
			if (setsockopt(huntsocket, SOL_SOCKET, SO_USELOOPBACK,
			    &option, sizeof option) < 0)
				warn("setsockopt loopback");
			errno = 0;
			if (connect(huntsocket, (struct sockaddr *) &Daemon,
			    DAEMON_SIZE) < 0) {
				if (errno != ECONNREFUSED) {
					leave(1, "connect");
				}
			}
			else
				break;
			sleep(1);
		} while (close(huntsocket) == 0);
#else /* !INTERNET */
		/*
		 * set up a socket
		 */

		if ((huntsocket = socket(SOCK_FAMILY, SOCK_STREAM, 0)) < 0)
			err(1, "socket");

		/*
		 * attempt to connect the socket to a name; if it fails that
		 * usually means that the driver isn't running, so we start
		 * up the driver.
		 */

		Daemon.sun_family = SOCK_FAMILY;
		(void) strcpy(Daemon.sun_path, huntsockpath);
		if (connect(huntsocket, &Daemon, DAEMON_SIZE) < 0) {
			if (errno != ENOENT) {
				leavex(1, "connect2");
			}
			start_driver();

			do {
				(void) close(huntsocket);
				if ((huntsocket = socket(SOCK_FAMILY, SOCK_STREAM,
				    0)) < 0)
					err(1, "socket");
				sleep(2);
			} while (connect(huntsocket, &Daemon, DAEMON_SIZE) < 0);
		}
#endif

		do_connect(name, sizeof(name), team, enter_status);
#ifdef INTERNET
		if (Send_message != NULL) {
			do_message();
			if (enter_status == Q_MESSAGE)
				break;
			Send_message = NULL;
			/* don't continue as that will call find_driver */
			goto jump_in;
		}
#endif
		playit();
		if ((enter_status = quit(enter_status)) == Q_QUIT)
			break;
	}
	leavex(0, NULL);
	/* NOTREACHED */
	return(0);
}
Пример #25
0
static void device_register(void *descriptors, uint16_t descriptors_len, usbh_device_t *dev)
{
	uint32_t i = 0;
	dev->drv = 0;
	uint8_t *buf = (uint8_t *)descriptors;

	dev->drv = 0;
	dev->drvdata = 0;

	uint8_t desc_len = buf[i];
	uint8_t desc_type = buf[i + 1];

	usbh_dev_driver_info_t device_info;
	if (desc_type == USB_DT_DEVICE) {
		struct usb_device_descriptor *device_desc = (void*)&buf[i];
		device_info.deviceClass = device_desc->bDeviceClass;
		device_info.deviceSubClass = device_desc->bDeviceSubClass;
		device_info.deviceProtocol = device_desc->bDeviceProtocol;
		device_info.idVendor = device_desc->idVendor;
		device_info.idProduct = device_desc->idProduct;
	} else {;
		return;
	}


	while (i < descriptors_len) {
		desc_len = buf[i];
		desc_type = buf[i + 1];
		switch (desc_type) {
		case USB_DT_INTERFACE:
		{
			struct usb_interface_descriptor *iface = (void*)&buf[i];
			device_info.ifaceClass = iface->bInterfaceClass;
			device_info.ifaceSubClass = iface->bInterfaceSubClass;
			device_info.ifaceProtocol = iface->bInterfaceProtocol;
			const usbh_dev_driver_t *driver = find_driver(&device_info);
			if (driver) {
				dev->drv = driver;
				dev->drvdata = dev->drv->init(dev);
				if (!dev->drvdata) {
				}
				break;
			}
		}
			break;
		default:
			break;
		}

		if (desc_len == 0) {
			return;
		}
		i += desc_len;

	}

	if (dev->drv && dev->drvdata) {
		// analyze descriptors
		i = 0;
		while (i < descriptors_len) {
			desc_len = buf[i];
			void *drvdata = dev->drvdata;
			if (dev->drv->analyze_descriptor(drvdata, &buf[i])) {
				return;
			}
			i += desc_len;
		}
	}
}
Пример #26
0
int
main(int argc, char **argv)
{
    AVFormatContext *afc;
    AVStream *st;
    AVPacket pk;
    struct frame_format frame_fmt = { 0 };
    const struct pixconv *pixconv = NULL;
    const struct memman *memman = NULL;
    const struct codec *codec = NULL;
    struct frame_format dp;
    int bufsize = BUFFER_SIZE;
    pthread_t dispt;
    unsigned flags = OFBP_DOUBLE_BUF;
    char *test_param = NULL;
    char *dispdrv = NULL;
    char *timer_drv = NULL;
    char *memman_drv = NULL;
    char *pixconv_drv = NULL;
    char *codec_drv = NULL;
    int opt;
    int ret = 0;

#define error(n) do { ret = n; goto out; } while (0)

    while ((opt = getopt(argc, argv, "b:d:fFM:P:st:T:v:")) != -1) {
        switch (opt) {
        case 'b':
            bufsize = strtol(optarg, NULL, 0) * 1048576;
            break;
        case 'd':
            dispdrv = optarg;
            break;
        case 'F':
            noaspect = 1;
        case 'f':
            flags |= OFBP_FULLSCREEN;
            break;
        case 'M':
            memman_drv = optarg;
            break;
        case 'P':
            pixconv_drv = optarg;
            break;
        case 's':
            flags &= ~OFBP_DOUBLE_BUF;
            break;
        case 't':
            test_param = optarg;
            break;
        case 'T':
            timer_drv = optarg;
            break;
        case 'v':
            codec_drv = optarg;
            break;
        }
    }

    argc -= optind;
    argv += optind;

    if (test_param)
        return speed_test(dispdrv, memman_drv, pixconv_drv, test_param, flags);

    if (argc < 1)
        return 1;

    av_register_all();
    avcodec_register_all();

    afc = open_file(argv[0]);

    st = find_stream(afc);
    if (!st) {
        fprintf(stderr, "No video streams found.\n");
        exit(1);
    }

    codec = find_driver(codec_drv, NULL, ofbp_codec_start);
    if (!codec) {
        fprintf(stderr, "Decoder '%s' not found\n", codec_drv);
        error(1);
    }

    if (codec->open(NULL, st->codec, &frame_fmt)) {
        fprintf(stderr, "Error opening decoder\n");
        error(1);
    }

    if (!frame_fmt.width) {
        fprintf(stderr, "Decoder error: frame size not specified\n");
        error(1);
    }

    dp.pixfmt = frame_fmt.pixfmt;
    display = display_open(dispdrv, &dp, &frame_fmt);
    if (!display)
        error(1);

    set_scale(&dp, &frame_fmt, flags);

    if (display->memman) {
        if (dp.pixfmt == frame_fmt.pixfmt) {
            memman = display->memman;
        } else if (display->flags & OFBP_PRIV_MEM) {
            fprintf(stderr, "Decoder/display pixel format mismatch\n");
            error(1);
        }
    }

    if (!memman)
        memman = find_driver(memman_drv, NULL, ofbp_memman_start);
    if (!memman)
        error(1);

    if ((codec->flags & OFBP_PHYS_MEM) && !(memman->flags & OFBP_PHYS_MEM)) {
        fprintf(stderr, "Incompatible decoder/memman\n");
        error(1);
    }

    if (memman->alloc_frames(&frame_fmt, bufsize, &frames, &num_frames))
        error(1);

    if (memman != display->memman) {
        pixconv = pixconv_open(pixconv_drv, &frame_fmt, &dp);
        if (!pixconv)
            error(1);
        if ((pixconv->flags & OFBP_PHYS_MEM) &&
            !(memman->flags & display->flags & OFBP_PHYS_MEM)) {
            fprintf(stderr, "Incompatible display/memman/pixconv\n");
            error(1);
        }
    }

    timer = timer_open(timer_drv);
    if (!timer)
        error(1);

    init_frames(&frame_fmt);

    if (display->enable(&frame_fmt, flags, pixconv, &dp))
        error(1);

    pthread_mutex_init(&disp_lock, NULL);
    sem_init(&disp_sem, 0, 0);

    signal(SIGINT, sigint);

    pthread_create(&dispt, NULL, disp_thread, st);

    while (!stop && !av_read_frame(afc, &pk)) {
        if (pk.stream_index == st->index)
            if (codec->decode(&pk))
                stop = 1;
        av_free_packet(&pk);
    }

    if (!stop) {
        sem_post(&disp_sem);
        while (disp_tail != -1)
            usleep(100000);
    }

    stop = 1;
    sem_post(&disp_sem);
    pthread_join(dispt, NULL);

out:
    if (afc) av_close_input_file(afc);

    if (codec)   codec->close();
    if (timer)   timer->close();
    if (memman)  memman->free_frames(frames, num_frames);
    if (display) display->close();
    if (pixconv) pixconv->close();

    return ret;
}
Пример #27
0
static int
speed_test(const char *drv, const char *mem, const char *conv,
           char *size, unsigned disp_flags)
{
    const struct pixconv *pixconv = NULL;
    const struct memman *memman = NULL;
    struct frame_format dp = { 0 };
    struct frame_format ff = { 0 };
    struct timespec t1, t2;
    unsigned w, h = 0;
    unsigned n = 1000;
    unsigned bufsize;
    char *ss = size;
    int i, j;

    w = strtoul(size, &size, 0);
    if (*size++)
        h = strtoul(size, &size, 0);
    if (*size++)
        n = strtoul(size, NULL, 0);

    if (!w || !h || !n) {
        fprintf(stderr, "Invalid size/count '%s'\n", ss);
        return 1;
    }

    ff.width  = ALIGN(w, 32);
    ff.height = ALIGN(h, 32);
    ff.disp_x = 0;
    ff.disp_y = 0;
    ff.disp_w = w;
    ff.disp_h = h;

    dp.pixfmt = ff.pixfmt = PIX_FMT_YUV420P;
    display = display_open(drv, &dp, &ff);
    if (!display)
        return 1;

    set_scale(&dp, &ff, disp_flags);

    if (display->memman) {
        memman = display->memman;
        ff.pixfmt = dp.pixfmt;
    }

    if (!memman)
        memman = find_driver(mem, NULL, ofbp_memman_start);

    if (memman->alloc_frames(&ff, 0, &frames, &num_frames))
        return 1;

    if (memman != display->memman) {
        pixconv = pixconv_open(conv, &ff, &dp);
        if (!pixconv)
            return 1;
        if ((pixconv->flags & OFBP_PHYS_MEM) &&
            !(memman->flags & display->flags & OFBP_PHYS_MEM)) {
            fprintf(stderr, "Incompatible display/memman/pixconv\n");
            return 1;
        }
    }

    init_frames(&ff);

    if (display->enable(&ff, disp_flags, pixconv, &dp))
        return 1;

    bufsize = ff.disp_w * ff.disp_h * 3 / 2;

    test_pattern(frames, num_frames, &ff);

    signal(SIGINT, sigint);

    clock_gettime(CLOCK_REALTIME, &t1);

    for (i = 0; i < n && !stop; i++) {
        struct frame *f = ofbp_get_frame();
        display->prepare(f);
        display->show(f);
    }

    clock_gettime(CLOCK_REALTIME, &t2);
    j = ts_diff_ms(&t2, &t1);
    fprintf(stderr, "%d ms, %d fps, read %lld B/s, write %lld B/s\n",
            j, i*1000 / j, 1000LL*i*bufsize / j, 2000LL*i*w*h / j);

    memman->free_frames(frames, num_frames);
    display->close();
    if (pixconv) pixconv->close();

    return 0;
}
Пример #28
0
void video_reset(struct dec_video *d_video)
{
    video_vd_control(d_video, VDCTRL_RESET, NULL);
    d_video->first_packet_pdts = MP_NOPTS_VALUE;
    d_video->start_pts = MP_NOPTS_VALUE;
    d_video->decoded_pts = MP_NOPTS_VALUE;
    d_video->codec_pts = MP_NOPTS_VALUE;
    d_video->codec_dts = MP_NOPTS_VALUE;
    d_video->last_format = d_video->fixed_format = (struct mp_image_params){0};
    d_video->dropped_frames = 0;
    d_video->current_state = DATA_AGAIN;
    mp_image_unrefp(&d_video->current_mpi);
    talloc_free(d_video->packet);
    d_video->packet = NULL;
    talloc_free(d_video->new_segment);
    d_video->new_segment = NULL;
    d_video->start = d_video->end = MP_NOPTS_VALUE;
}

int video_vd_control(struct dec_video *d_video, int cmd, void *arg)
{
    const struct vd_functions *vd = d_video->vd_driver;
    if (vd)
        return vd->control(d_video, cmd, arg);
    return CONTROL_UNKNOWN;
}

void video_uninit(struct dec_video *d_video)
{
    if (!d_video)
        return;
    mp_image_unrefp(&d_video->current_mpi);
    mp_image_unrefp(&d_video->cover_art_mpi);
    if (d_video->vd_driver) {
        MP_VERBOSE(d_video, "Uninit video.\n");
        d_video->vd_driver->uninit(d_video);
    }
    talloc_free(d_video->packet);
    talloc_free(d_video->new_segment);
    talloc_free(d_video);
}

static int init_video_codec(struct dec_video *d_video, const char *decoder)
{
    if (!d_video->vd_driver->init(d_video, decoder)) {
        MP_VERBOSE(d_video, "Video decoder init failed.\n");
        return 0;
    }
    return 1;
}

struct mp_decoder_list *video_decoder_list(void)
{
    struct mp_decoder_list *list = talloc_zero(NULL, struct mp_decoder_list);
    for (int i = 0; mpcodecs_vd_drivers[i] != NULL; i++)
        mpcodecs_vd_drivers[i]->add_decoders(list);
    return list;
}

static struct mp_decoder_list *mp_select_video_decoders(const char *codec,
                                                        char *selection)
{
    struct mp_decoder_list *list = video_decoder_list();
    struct mp_decoder_list *new = mp_select_decoders(list, codec, selection);
    talloc_free(list);
    return new;
}

static const struct vd_functions *find_driver(const char *name)
{
    for (int i = 0; mpcodecs_vd_drivers[i] != NULL; i++) {
        if (strcmp(mpcodecs_vd_drivers[i]->name, name) == 0)
            return mpcodecs_vd_drivers[i];
    }
    return NULL;
}

bool video_init_best_codec(struct dec_video *d_video)
{
    struct MPOpts *opts = d_video->opts;

    assert(!d_video->vd_driver);
    video_reset(d_video);
    d_video->has_broken_packet_pts = -10; // needs 10 packets to reach decision

    struct mp_decoder_entry *decoder = NULL;
    struct mp_decoder_list *list =
        mp_select_video_decoders(d_video->codec->codec, opts->video_decoders);

    mp_print_decoders(d_video->log, MSGL_V, "Codec list:", list);

    for (int n = 0; n < list->num_entries; n++) {
        struct mp_decoder_entry *sel = &list->entries[n];
        const struct vd_functions *driver = find_driver(sel->family);
        if (!driver)
            continue;
        MP_VERBOSE(d_video, "Opening video decoder %s:%s\n",
                   sel->family, sel->decoder);
        d_video->vd_driver = driver;
        if (init_video_codec(d_video, sel->decoder)) {
            decoder = sel;
            break;
        }
        d_video->vd_driver = NULL;
        MP_WARN(d_video, "Video decoder init failed for "
                "%s:%s\n", sel->family, sel->decoder);
    }

    if (d_video->vd_driver) {
        d_video->decoder_desc =
            talloc_asprintf(d_video, "%s [%s:%s]", decoder->desc, decoder->family,
                            decoder->decoder);
        MP_VERBOSE(d_video, "Selected video codec: %s\n", d_video->decoder_desc);
    } else {
        MP_ERR(d_video, "Failed to initialize a video decoder for codec '%s'.\n",
               d_video->codec->codec);
    }

    if (d_video->header->missing_timestamps) {
        MP_WARN(d_video, "This stream has no timestamps!\n");
        MP_WARN(d_video, "Making up playback time using %f FPS.\n", d_video->fps);
        MP_WARN(d_video, "Seeking will probably fail badly.\n");
    }

    talloc_free(list);
    return !!d_video->vd_driver;
}

static void fix_image_params(struct dec_video *d_video,
                             struct mp_image_params *params)
{
    struct MPOpts *opts = d_video->opts;
    struct mp_image_params p = *params;
    struct mp_codec_params *c = d_video->codec;

    MP_VERBOSE(d_video, "Decoder format: %s\n", mp_image_params_to_str(params));

    // While mp_image_params normally always have to have d_w/d_h set, the
    // decoder signals unknown bitstream aspect ratio with both set to 0.
    float dec_aspect = p.p_w > 0 && p.p_h > 0 ? p.p_w / (float)p.p_h : 0;
    if (d_video->initial_decoder_aspect == 0)
        d_video->initial_decoder_aspect = dec_aspect;

    bool use_container = true;
    switch (opts->aspect_method) {
    case 0:
        // We normally prefer the container aspect, unless the decoder aspect
        // changes at least once.
        if (dec_aspect > 0 && d_video->initial_decoder_aspect != dec_aspect) {
            MP_VERBOSE(d_video, "Using bitstream aspect ratio.\n");
            // Even if the aspect switches back, don't use container aspect again.
            d_video->initial_decoder_aspect = -1;
            use_container = false;
        }
        break;
    case 1:
        use_container = false;
        break;
    }

    if (use_container && c->par_w > 0 && c->par_h) {
        MP_VERBOSE(d_video, "Using container aspect ratio.\n");
        p.p_w = c->par_w;
        p.p_h = c->par_h;
    }

    if (opts->movie_aspect >= 0) {
        MP_VERBOSE(d_video, "Forcing user-set aspect ratio.\n");
        if (opts->movie_aspect == 0) {
            p.p_w = p.p_h = 1;
        } else {
            AVRational a = av_d2q(opts->movie_aspect, INT_MAX);
            mp_image_params_set_dsize(&p, a.num, a.den);
        }
    }

    // Assume square pixels if no aspect ratio is set at all.
    if (p.p_w <= 0 || p.p_h <= 0)
        p.p_w = p.p_h = 1;

    // Detect colorspace from resolution.
    mp_image_params_guess_csp(&p);

    d_video->last_format = *params;
    d_video->fixed_format = p;
}

static struct mp_image *decode_packet(struct dec_video *d_video,
                                      struct demux_packet *packet,
                                      int drop_frame)
{
    struct MPOpts *opts = d_video->opts;

    if (!d_video->vd_driver)
        return NULL;

    double pkt_pts = packet ? packet->pts : MP_NOPTS_VALUE;
    double pkt_dts = packet ? packet->dts : MP_NOPTS_VALUE;

    if (pkt_pts == MP_NOPTS_VALUE)
        d_video->has_broken_packet_pts = 1;

    double pkt_pdts = pkt_pts == MP_NOPTS_VALUE ? pkt_dts : pkt_pts;
    if (pkt_pdts != MP_NOPTS_VALUE && d_video->first_packet_pdts == MP_NOPTS_VALUE)
        d_video->first_packet_pdts = pkt_pdts;

    MP_STATS(d_video, "start decode video");

    struct mp_image *mpi = d_video->vd_driver->decode(d_video, packet, drop_frame);

    MP_STATS(d_video, "end decode video");

    // Error, discarded frame, dropped frame, or initial codec delay.
    if (!mpi || drop_frame) {
        talloc_free(mpi);
        return NULL;
    }

    if (opts->field_dominance == 0) {
        mpi->fields |= MP_IMGFIELD_TOP_FIRST | MP_IMGFIELD_INTERLACED;
    } else if (opts->field_dominance == 1) {
        mpi->fields &= ~MP_IMGFIELD_TOP_FIRST;
        mpi->fields |= MP_IMGFIELD_INTERLACED;
    }

    // Note: the PTS is reordered, but the DTS is not. Both should be monotonic.
    double pts = mpi->pts;
    double dts = mpi->dts;

    if (pts != MP_NOPTS_VALUE) {
        if (pts < d_video->codec_pts)
            d_video->num_codec_pts_problems++;
        d_video->codec_pts = mpi->pts;
    }

    if (dts != MP_NOPTS_VALUE) {
        if (dts <= d_video->codec_dts)
            d_video->num_codec_dts_problems++;
        d_video->codec_dts = mpi->dts;
    }

    if (d_video->has_broken_packet_pts < 0)
        d_video->has_broken_packet_pts++;
    if (d_video->num_codec_pts_problems)
        d_video->has_broken_packet_pts = 1;

    // If PTS is unset, or non-monotonic, fall back to DTS.
    if ((d_video->num_codec_pts_problems > d_video->num_codec_dts_problems ||
         pts == MP_NOPTS_VALUE) && dts != MP_NOPTS_VALUE)
        pts = dts;

    if (!opts->correct_pts || pts == MP_NOPTS_VALUE) {
        if (opts->correct_pts && !d_video->header->missing_timestamps)
            MP_WARN(d_video, "No video PTS! Making something up.\n");

        double frame_time = 1.0f / (d_video->fps > 0 ? d_video->fps : 25);
        double base = d_video->first_packet_pdts;
        pts = d_video->decoded_pts;
        if (pts == MP_NOPTS_VALUE) {
            pts = base == MP_NOPTS_VALUE ? 0 : base;
        } else {
            pts += frame_time;
        }
    }

    if (!mp_image_params_equal(&d_video->last_format, &mpi->params))
        fix_image_params(d_video, &mpi->params);

    mpi->params = d_video->fixed_format;

    mpi->pts = pts;
    d_video->decoded_pts = pts;

    // Compensate for incorrectly using mpeg-style DTS for avi timestamps.
    if (d_video->codec->avi_dts && opts->correct_pts &&
        mpi->pts != MP_NOPTS_VALUE && d_video->fps > 0)
    {
        int delay = -1;
        video_vd_control(d_video, VDCTRL_GET_BFRAMES, &delay);
        mpi->pts -= MPMAX(delay, 0) / d_video->fps;
    }

    return mpi;
}

void video_reset_aspect(struct dec_video *d_video)
{
    d_video->last_format = (struct mp_image_params){0};
}

void video_set_framedrop(struct dec_video *d_video, bool enabled)
{
    d_video->framedrop_enabled = enabled;
}

// Frames before the start timestamp can be dropped. (Used for hr-seek.)
void video_set_start(struct dec_video *d_video, double start_pts)
{
    d_video->start_pts = start_pts;
}

void video_work(struct dec_video *d_video)
{
    if (d_video->current_mpi)
        return;

    if (d_video->header->attached_picture) {
        if (d_video->current_state == DATA_AGAIN && !d_video->cover_art_mpi) {
            d_video->cover_art_mpi =
                decode_packet(d_video, d_video->header->attached_picture, 0);
            // Might need flush.
            if (!d_video->cover_art_mpi)
                d_video->cover_art_mpi = decode_packet(d_video, NULL, 0);
            d_video->current_state = DATA_OK;
        }
        if (d_video->current_state == DATA_OK)
            d_video->current_mpi = mp_image_new_ref(d_video->cover_art_mpi);
        // (DATA_OK is returned the first time, when current_mpi is sill set)
        d_video->current_state = DATA_EOF;
        return;
    }

    if (!d_video->packet && !d_video->new_segment &&
        demux_read_packet_async(d_video->header, &d_video->packet) == 0)
    {
        d_video->current_state = DATA_WAIT;
        return;
    }

    if (d_video->packet) {
        if (d_video->packet->dts == MP_NOPTS_VALUE && !d_video->codec->avi_dts)
            d_video->packet->dts = d_video->packet->pts;
    }

    if (d_video->packet && d_video->packet->new_segment) {
        assert(!d_video->new_segment);
        d_video->new_segment = d_video->packet;
        d_video->packet = NULL;
    }

    bool had_input_packet = !!d_video->packet;
    bool had_packet = had_input_packet || d_video->new_segment;

    double start_pts = d_video->start_pts;
    if (d_video->start != MP_NOPTS_VALUE && (start_pts == MP_NOPTS_VALUE ||
                                             d_video->start > start_pts))
        start_pts = d_video->start;

    int framedrop_type = d_video->framedrop_enabled ? 1 : 0;
    if (start_pts != MP_NOPTS_VALUE && d_video->packet &&
        d_video->packet->pts < start_pts - .005 &&
        !d_video->has_broken_packet_pts)
    {
        framedrop_type = 2;
    }
    d_video->current_mpi = decode_packet(d_video, d_video->packet, framedrop_type);
    if (d_video->packet && d_video->packet->len == 0) {
        talloc_free(d_video->packet);
        d_video->packet = NULL;
    }

    d_video->current_state = DATA_OK;
    if (!d_video->current_mpi) {
        d_video->current_state = DATA_EOF;
        if (had_packet) {
            if (framedrop_type == 1)
                d_video->dropped_frames += 1;
            d_video->current_state = DATA_AGAIN;
        }
    }

    bool segment_ended = !d_video->current_mpi && !had_input_packet;

    if (d_video->current_mpi && d_video->current_mpi->pts != MP_NOPTS_VALUE) {
        double vpts = d_video->current_mpi->pts;
        segment_ended = d_video->end != MP_NOPTS_VALUE && vpts >= d_video->end;
        if ((d_video->start != MP_NOPTS_VALUE && vpts < d_video->start)
            || segment_ended)
        {
            talloc_free(d_video->current_mpi);
            d_video->current_mpi = NULL;
        }
    }

    // If there's a new segment, start it as soon as we're drained/finished.
    if (segment_ended && d_video->new_segment) {
        struct demux_packet *new_segment = d_video->new_segment;
        d_video->new_segment = NULL;

        // Could avoid decoder reinit; would still need flush.
        d_video->codec = new_segment->codec;
        if (d_video->vd_driver)
            d_video->vd_driver->uninit(d_video);
        d_video->vd_driver = NULL;
        video_init_best_codec(d_video);

        d_video->start = new_segment->start;
        d_video->end = new_segment->end;

        new_segment->new_segment = false;

        d_video->packet = new_segment;
        d_video->current_state = DATA_AGAIN;
    }
}

// Fetch an image decoded with video_work(). Returns one of:
//  DATA_OK:    *out_mpi is set to a new image
//  DATA_WAIT:  waiting for demuxer; will receive a wakeup signal
//  DATA_EOF:   end of file, no more frames to be expected
//  DATA_AGAIN: dropped frame or something similar
int video_get_frame(struct dec_video *d_video, struct mp_image **out_mpi)
{
    *out_mpi = NULL;
    if (d_video->current_mpi) {
        *out_mpi = d_video->current_mpi;
        d_video->current_mpi = NULL;
        return DATA_OK;
    }
    if (d_video->current_state == DATA_OK)
        return DATA_AGAIN;
    return d_video->current_state;
}